Java虚拟机之HotSpot虚拟机

本文深入探讨了Java对象的创建过程,包括类加载检查、内存分配(指针碰撞与空闲列表)、初始化零值、设置对象头以及执行构造器。讲解了对象头的MarkWord和类型指针,并分析了对象在堆中的内存布局。此外,还介绍了对象访问定位的两种方式:句柄访问和直接指针访问,以及它们各自的优缺点。最后,通过JOL工具展示了对象占用的内存情况。
摘要由CSDN通过智能技术生成

一、HotSpot虚拟机

在这里插入图片描述

二、对象的创建

Java对象的创建可以分为五个步骤:

  1. 检查类加载
  2. 分配内存
  3. 初始化零值
  4. 设置对象头
  5. 执行实例构造器

下面我将介绍这五个部分的内容:
1、类加载检查
HotSpot虚拟机遇到一条new指令,会先检查能否在常量池中定位到这个类的符号引用,检查这个类是否类加载过,按照下面情况进行处理:

  1. 没有类加载过就去类加载
  2. 类加载过就进行下一步分配内存

2、分配内存
虚拟机在堆上为新对象分配内存,有两种内存分配的方式:

  1. 指针碰撞
  2. 空闲列表

1)指针碰撞

  1. 使用场景: 堆内存规整整齐
  2. 过程:使用过的空间放在一边,空闲的空间放在另一边,中间有一个指针作为分界点指示器,把新生对象放在使用过空间的那一边,中间指针向空闲空间那边挪动一个新生对象的内存大小的距离即可
  3. 特点:简单,高效,因为要堆内存规整整齐,所以垃圾收集器应该要有压缩整理的能力

2) 空闲列表

  1. 使用场景: 已使用空间和空闲空间交错在一起

  2. 过程: 虚拟机维护一个列表,列表中记录了哪些内存空间可用,分配时找一块足够大的内存空间划分给新生对象,然后更新列表

  3. 特点: 比指针碰撞复杂, 但是对垃圾收集器可以不用压缩整理的能力

3、初始化零值
分配内存完成后,虚拟机将分配的内存空间初始化为零值(不包括对象头) ,这样保证了对象的成员字段(成员变量)在Java代码中不赋初始值就可以使用。

4、设置对象头
把一些信息(这个对象属于哪个类? 对象哈希码,对象GC分代年龄)存放在对象头中 (后面详细说明对象头)

5、执行init方法
一般的初始化方法就是实例变量赋值 、实例代码块和实例构造器三个部分组成,其一般公式如下:
init方法 = 实例变量赋值 + 实例代码块 + 实例构造器

对象的内存布局

三、对象内存信息

对象在堆中的内存布局可以分为三个部分组成:

  1. 对象头
  2. 实例数据
  3. 对齐填充

1、对象头包括两类信息(8Byte + 4Byte)
4. Mark Word:用于存储该对象自身运行时数据(该对象的哈希码信息,GC信息:分代年龄,锁信息:状态标志等)
5. 类型指针(对象指向它类型元数据的指针):HotSpot通过类型指针确定该对象是哪个类的实例 (如果该对象是数组,对象头中还必须记录数组的长度) 类型指针默认是压缩指针,内存超过32G时为了寻址就不能采用压缩指针了

2、实例数据是对象真正存储的有效信息

  1. 记录从父类中继承的字段和该类中定义的字段

  2. 父类的字段会出现在子类字段之前,默认子类较小的字段可以插入父类字段间的空隙以此来节约空间(+XX:CompactFields)

3、对齐填充

HotSpot要求对象起始地址必须是8字节整倍数 。因此,任何对象的大小都必须是8字节的整倍,如果对象实例数据部分未到达8字节就会通过对齐填充进行补全

四、对象头

分析对象占用对晒需要导入JOL依赖:

<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
        <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.12</version>
        </dependency>

新建对象的各个占用情况如下:
1、mark word : 8 byte
2、类型指针: 4 byte
3、对齐填充 12->16 byte
JVM的结构图
下图为JVM的虚拟机的结构图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yr6K7D6u-1638620866694)(HotSpot虚拟机对象探秘.assets/image-20210429190053375.png)]

五、对象的访问定位

1、Java程序通过栈上的reference类型数据来操作堆上的对象,其访问方式如下:

  1. 对象实例数据: 对象的有效信息字段等(就是上面说的数据)
  2. 对象类型数据: 该对象所属类的类信息(存于方法区中)

2、句柄访问方式
在堆中开辟一块内存作为句柄池,栈中的reference数据存储的是该对象句柄池的地址,句柄中包含了对象实例数据和对象类型数据

  1. 优点: 稳定,对象被移动时(压缩或复制算法),只需要改动该句柄的对象实例数据指针
  2. 缺点: 多一次间接访问的开销

3、 直接指针访问

栈中的reference数据存储堆中该对象的地址(reference指向该对象),但是对象的内存布局需要保存对象类型数据,其优缺点如下:

  1. 优点: 访问速度快
  2. 缺点: 不稳定,对象被移动时(压缩或复制算法),需要改动指针
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

绝域时空

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值