JVM学习笔记九:对象实例化与直接内存

news2024/11/15 13:49:45

0. 前言

声明:
感谢尚硅谷宋红康老师的讲授。
感谢广大网友共享的笔记内容。
B站:https://www.bilibili.com/video/BV1PJ411n7xZ
本文的内容基本来源于宋老师的课件,其中有一些其他同学共享的内容,也有一些自己的理解内容。

1. 对象的实例化

对象的实例化
其中的介绍:
判断对象对应的类是否加载、链接、初始化
虚拟机遇到一条new指令,首先去检查这个指令的参数能否在Metaspace的常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载,解析和初始化(即判断类元信息是否存在)。

如果没有,那么在双亲委派模式下,使用当前类加载器以ClassLoader + 包名 + 类名为key进行查找对应的 .class文件;
- 如果没有找到文件,则抛出ClassNotFoundException异常
- 如果找到,则进行类加载,并生成对应的Class对象

为对象分配内存
首先计算对象占用空间的大小,接着在堆中划分一块内存给新对象。如果实例成员变量是引用变量,仅分配引用变量空间即可,即4个字节大小
如果内存规整:虚拟机将采用的是**指针碰撞法(Bump The Point)**来为对象分配内存。
- 意思是所有用过的内存在一边,空闲的内存放另外一边,中间放着一个指针作为分界点的指示器,分配内存就仅仅是把指针指向空闲那边挪动一段与对象大小相等的距离罢了。如果垃圾收集器选择的是Serial ,ParNew这种基于压缩算法的,虚拟机采用这种分配方式。一般使用带Compact(整理)过程的收集器时,使用指针碰撞。

如果内存不规整:虚拟机需要维护一个空闲列表(Free List)来为对象分配内存。
- 已使用的内存和未使用的内存相互交错,那么虚拟机将采用的是空闲列表来为对象分配内存。意思是虚拟机维护了一个列表,记录上那些内存块是可用的,再分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的内容。

选择哪种分配方式由Java堆是否规整所决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。

处理并发问题

  • 采用CAS失败重试、区域加锁保证更新的原子性
  • 每个线程预先分配一块TLAB:通过设置 -XX:+UseTLAB参数来设定

初始化分配到的内存
所有属性设置默认值,保证对象实例字段在不赋值时可以直接使用

设置对象的对象头
将对象的所属类(即类的元数据信息)、对象的 HashCode 和对象的 GC 信息、锁信息等数据存储在对象的对象头中。这个过程的具体设置方式取决于JVM实现。

执行init方法进行初始化
在Java程序的视角看来,初始化才正式开始。初始化成员变量,执行实例化代码块,调用类的构造方法,并把堆内对象的首地址赋值给引用变量。

因此一般来说(由字节码中跟随invokespecial指令所决定),new指令之后会接着就是执行方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完成创建出来。

给对象属性赋值的操作

  1. 属性的默认初始化
  2. 显示初始化
  3. 代码块中的初始化
  4. 构造器中的初始化

对象实例化的过程

  1. 加载类的元信息
  2. 为对象分配内存
  3. 处理并发问题
  4. 属性的默认初始化(零值初始化)
  5. 设置对象头信息
  6. 属性的显示初始化、代码块中初始化、构造器中初始化

2. 对象的内存布局

对象的内存布局总览

  • 2.1 对象头(Header)
    对象头分为两个部分:1. 运行时元数据(Mark Word)2. 类型指针。 如果创建的是一个 Array 类型的对象,还需要在对象头中保存数组的长度信息。

运行时元数据(Mark Word)
● 哈希值(HashCode)
● GC分代年龄
● 锁状态标志
● 线程持有的锁
● 偏向线程ID
● 翩向时间戳

类型指针
指向类元数据 InstanceClass,确定该对象所属的类型。

  • 2.2 实例数据(Instance Data)
    它是对象真正存储的有效信息,包括程序代码中定义的各种类型的字段(包括从父类继承下来的和本身拥有的字段)

  • 相同宽度的字段总是被分配在一起

  • 父类中定义的变量会出现在子类之前

  • 如果CompactFields参数为true(默认为true):子类的窄变量可能插入到父类变量的空隙

  • 2.3 对齐填充
    不是必须的,也没有特别的含义,仅仅起到占位符的作用

图例说明
对象的内存布局1
对象的内存布局2

3. 对象的访问定位

访问方式的思维导图

JVM是如何通过栈帧中的对象引用访问到其内部的对象实例呢?
对象的访问定位

3.1 句柄访问

句柄访问
优点:Reference 中存储稳定的句柄地址,当垃圾回收器工作时对象被移动(标记整理算法),这时候只需要改变句柄中的实例数据指针即可,Reference 本身不需要被修改。
缺点:需要额外的使用句柄池,占用空间。

3.2 直接指针(HotSpot采用)

直接指针
优点:直接指针是局部变量表中的引用,直接指向堆中的实例,在对象实例中有类型指针,指向的是方法区中的对象类型数据
缺点:句柄访问的优点。

4. 直接内存

4.1 直接内存概述

不是虚拟机运行时数据区的一部分,也不是《Java虚拟机规范》中定义的内存区域。直接内存是在Java堆外的、直接向系统申请的内存区间。来源于NIO,通过存在堆中的DirectByteBuffer操作Native内存。通常,访问直接内存的速度会优于Java堆,即读写性能高。

  • 因此出于性能考虑,读写频繁的场合可能会考虑使用直接内存。
  • Java的NIO库允许Java程序使用直接内存,用于数据缓冲区

4.2 非直接缓存区

使用IO读写文件,需要与磁盘交互,需要由用户态切换到内核态。在内核态时,需要两份内存存储重复数据,效率低。
非直接缓存区访问方式

4.3 直接缓存区

使用NIO时,操作系统划出的直接缓存区可以被 java 代码直接访问,只有一份。NIO适合对大文件的读写操作。
直接缓存区访问方式
也可能导致 OutOfMemoryError 异常

public class DirectMemoryOutOf {
    private static final int BUFFER = 1024 * 1024 * 20;//20MB
    public static void main(String[] args) {
        ArrayList<ByteBuffer> list = new ArrayList<>();
        int count = 0;
        try {
            while(true){
                ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER);
                list.add(byteBuffer);
                count++;
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        } finally {
            System.out.println(count);
        }
    }
}

Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory 
    at java.nio.Bits.reserveMemory(Bits.java:693)
    at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)
    at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)
    at com.atguigu.java.BufferTest2.main(BufferTest2.java:20)

异常结果

由于直接内存在Java堆外,因此它的大小不会直接受限于 -Xmx 指定的最大堆大小,但是系统内存是有限的,Java堆和直接内存的总和依然受限于操作系统能给出的最大内存。

  • 分配回收成本较高
  • 不受JVM内存回收管理

直接内存大小可以通过 MaxDirectMemorySize 设置。如果不指定,默认与堆的最大值 -Xmx 参数值一致。
JDK7与JDK8的变化
例子:

package com.hhyy;
import java.nio.ByteBuffer;
import java.util.Scanner;
/*
以下程序执行后,可以通过任务管理器查看Java进行的占用情况。
 */
public class TestDirectMemory {
    static int memorySize = 1024 * 1024 * 1024; // 1GB
    public static void main(String[] args) {
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(memorySize);
        System.out.println("分配直接内存....");

        Scanner in = new Scanner(System.in);
        in.next();

        byteBuffer = null;
        System.out.println("直接内存被释放");


        System.gc();
        in.next();
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/400896.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文解码:如何在人工智能热潮下实现产业“智”变

近期由ChatGPT有关人工智能的话题引发了全民热议&#xff0c;在这股子浪潮下&#xff0c;讨论最多的话题就是ChatGPT的出现会为我们带来怎样的技术变革&#xff1f;是否会改变我们目前的生产方式&#xff1f;对于未来人工智能技术的发展&#xff0c;我们该如何客观看待&#xf…

Unity Lighting -- 使用Light Probes

什么是动态物体&#xff08;dynamic objects&#xff09; 到目前为止的例子中&#xff0c;我们场景中的所有东西都是静止的。但在实际的游戏或实时应用中&#xff0c;场景中有移动的物体很正常&#xff0c;比如走动的人或动物&#xff0c;汽车&#xff0c;飞机等&#xff0c;它…

MRCP在美团语音交互中的实践和应用

当你和智能语音机器人对话交互时&#xff0c;你是否好奇电话背后的机器人如何“听懂”你的意思&#xff0c;又如何像人一样“回答”你的问题&#xff1f;其中比较重要的技术就是 MRCP。本文主要介绍了 MRCP 在美团语音交互中的实践和应用&#xff0c;基于美团自研的语音识别及语…

动态规划入门经典问题讲解

最近开始接触动态规划问题&#xff0c;以下浅谈&#xff08;或回顾&#xff09;一下这些问题的求解过程。解题思路对于动态规划问题&#xff0c;由于最终问题的求解需要以同类子问题作为基础&#xff0c;故需要定义一个dp数组&#xff08;一维或二维&#xff09;来记录问题求解…

Vue 3.0 单文件组件 【Vue3 从零开始】

#介绍 在很多 Vue 项目中&#xff0c;我们使用 app.component 来定义全局组件&#xff0c;紧接着用 app.mount(#app) 在每个页面内指定一个容器元素。 这种方式在很多中小规模的项目中运作的很好&#xff0c;在这些项目里 JavaScript 只被用来加强特定的视图。但当在更复杂的…

[Java·算法·中等]LeetCode39. 组合总和

每天一题&#xff0c;防止痴呆题目示例分析思路1题解1分析思路2题解2&#x1f449;️ 力扣原文 题目 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形…

Golang Map实现原理分析与解读

一、map的结构与设计原理 golang中map是一个kv对集合。底层使用hash table&#xff0c;用链表来解决冲突 &#xff0c;出现冲突时&#xff0c;不是每一个key都申请一个结构通过链表串起来&#xff0c;而是以bmap为最小粒度挂载&#xff0c;一个bmap可以放8个kv。在哈希函数的选…

配置临时SSL子域名泛化证书

配置临时SSL子域名泛化证书 三个月有效期第一步&#xff1a;访问SSL证书地址第二步&#xff1a;在华为云上/其他服务器上搜索DNS云解析服务类似的功能第三步&#xff1a;将SSL申请的信息添加到服务器的记录集中第四步&#xff1a;添加完信息进行保存获取key / crt第五步&#x…

蓝桥冲刺31天之第七天

目录 A&#xff1a;三角回文数 B&#xff1a;数数 C&#xff1a;数组切分 D&#xff1a;倍数问题 一星陨落&#xff0c;黯淡不了星空灿烂&#xff1b; 一花凋零&#xff0c;荒芜不了整个春天。 如果命运是世界上最烂的编剧&#xff0c; 你就要争取做人生最好的演员。 即使生…

06_02_Spark Streaming

Spark Streaming 课程目标 说出Spark Streaming的特点说出DStreaming的常见操作api能够应用Spark Streaming实现实时数据处理能够应用Spark Streaming的状态操作解决实际问题独立实现foreachRDD向mysql数据库的数据写入独立实现Spark Streaming对接kafka实现实时数据处理 1、…

打怪升级之CFileDialog类介绍

CFileDialog类 CFileDialog封装用于文件打开操作或文件保存操作的常见对话框。信息来源自Windows官方文档&#xff1a;https://learn.microsoft.com/zh-cn/cpp/mfc/reference/cfiledialog-class?viewmsvc-170 这里重点介绍几个常用的函数功能&#xff1a; 构造函数 explic…

当我在ChatGPT上问重建大师,它居然这样回答我

最近&#xff0c;ChatGPT风靡全球&#xff0c;现象级走红至各大社交媒体。作为最快突破1亿月活量的消费者应用&#xff0c;是怎么样理解重建大师的呢&#xff1f; 今天小编与ChatGPT展开对话&#xff0c;它告诉我&#xff1a; 短短不到一分钟时间&#xff0c;ChatGPT已经概括出…

Grafana 监控面板绘制流程

本篇作者&#xff1a;IoTDB 社区 -- 张洪胤本文以 IoTDB V1.0.1 版本为例本文档介绍了 Apache IoTDB 监控指标通过 Prometheus 的方式进行采集&#xff0c;并且使用 Grafana 的方式进行可视化。1监控指标的 Prometheus 格式说明对于 Metric Name 为 name, Tags 为 K1V1, ..., K…

ABB机器人Offs坐标偏移功能的具体使用方法

ABB机器人Offs坐标偏移功能的具体使用方法 Offs功能说明: 在机器人的工件坐标系中添加一个偏移量 举例说明: 参数及数据类型: 在RobotStudio的仿真操作: 如下图所示,在程序中添加一个移动指令,并记录该点位为p10, 如下图所示,复制该指令语句, 如下图所示,选中…

Qt音视频开发22-音频播放QAudioOutput

一、前言 以前一直以为只有Qt5以后才有QAudioOutput播放音频&#xff0c;其实从Qt4.6开始就有&#xff0c;在Qt6中变成了QAudioSink&#xff0c;功能一样。用QAudioOutput播放音频pcm数据极其方便&#xff0c;只需要指定音频播放设备&#xff08;可能电脑上有多个音频输出设备…

力扣sql简单篇练习(二十六)

力扣sql简单篇练习(二十六) 1 每家商店的产品价格 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # 多行变成多列,考虑用sum if分组 SELECT product_id,sum(IF(storestore1,price,null)) store1,sum(IF(storestore2,price,null)) store2, sum(IF(st…

mmdetectionV2.x版本 训练自己的VOC数据集

mmdetection目录下创建data文件夹&#xff0c;路劲如图所示&#xff0c;不带yololabels 修改配置文件 mmdet/datasets/voc.py 配置图片格式 mmdet/datasets/xml_style.py 如果图片是jpg则改成jpg&#xff0c;是png格式就改成png&#xff0c;这里我不需要改&#xff0c;本…

C++11:包装器

文章目录1. 介绍2. function包装器2.1 介绍2.2 示例1用法2.3 示例22.4 function包装器的功能统一类型简化代码2.5 意义3. bind包装器3.1 介绍3.2 bind包装器的功能绑定固定参数3.3 意义1. 介绍 C 包装器是一种用于给其他编程接口提供更一致或更合适的接口的技术。它可以包装任…

人工智能书籍——《奇点临近》

当人们看到太多相同的时候&#xff0c;也许我们很无知&#xff1b; 当人们看到太多不同的时候&#xff0c;也许我们视野不够大&#xff1b; 当人们同时看到不同和相同的时候&#xff0c;也许这恰是我们的智慧原点。 物质是静止的能量&#xff0c;能量是运动的物质&#xff0c;生…

04 HiveHBase

Hive 一 Hive基本概念 1 Hive简介 学习目标 了解什么是Hive了解为什么使用Hive 1.1 什么是 Hive Hive 由 Facebook 实现并开源&#xff0c;是基于 Hadoop 的一个数据仓库工具&#xff0c;可以将结构化的数据映射为一张数据库表&#xff0c;并提供 HQL(Hive SQL)查询功能&…