zl程序教程

您现在的位置是:首页 >  其他

当前栏目

HotSpot VM 创建对象的实现原理

原理 实现 VM 创建对象 HotSpot
2023-09-11 14:14:53 时间

1 HotSpot VM

HotSpot VM,它是Sun JDK和OpenJDK中所带的虚拟机,也是目前使用范围最广的Java虚拟机。

JVM是虚拟机,总的来说是一种标准规范,虚拟机有很多实现版本。主要作用就是运行java的类文件的。而HotSpot是虚拟机的一种实现,它是sun公司开发的,是sun jdk和open jdk中自带的虚拟机。

二者区别是一个是标准,一个是实现方式。

2 HotSpot 中对象的创建

2.1 加载

遇到 new 指令时,首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已经被加载、解析和初始化过。如果没有,执行相应的类加载。

2.2 分配内存

类加载检查通过之后,接下来从堆中划分一块对应大小的内存空间给新的对象。分配堆内存有两种方式:

  • 指针碰撞
    如果Java堆中内存绝对规整(说明采用的是“复制算法”或“标记整理法”)

所有被使用过的内存都放到一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,

那所分配内存就是仅仅把那个指针向空闲空间方向挪动一段与对象大小相等的距离

  • 空闲列表
    如果Java堆中内存并不规整,已使用的内存和空间内存交错(说明采用的是标记-清除法,有碎片),此时没办法简单进行指针碰撞,VM必须维护一个列表,记录其中哪些内存块空闲可用。分配之时从空闲列表中找到一块足够大的内存空间划分给对象实例。这种方式称为“空闲列表”。
2.3 初始化

内存空间分配完成后会初始化为 0(不包括对象头),接下来就是填充对象头,把对象是哪个类的实例、如何才能找到类的元数据信息、对象的哈希码、对象的 GC 分代年龄等信息存入对象头。
执行 new 指令后执行 init 方法后才算一份真正可用的对象创建完成。

3 对象的内存布局

在 HotSpot 虚拟机中,分为 3 块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)

3.1 对象头(Header)

包含两部分,第一部分用于存储对象自身的运行时数据,如哈希码、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等,32 位虚拟机占 32 bit,64 位虚拟机占 64 bit。官方称为 ‘Mark Word’。
第二部分是类型指针,即对象指向它的类的元数据指针,虚拟机通过这个指针确定这个对象是哪个类的实例。另外,如果是 Java 数组,对象头中还必须有一块用于记录数组长度的数据,因为普通对象可以通过 Java 对象元数据确定大小,而数组对象不可以。

3.2 实例数据(Instance Data)

程序代码中所定义的各种类型的字段内容(包含父类继承下来的和子类中定义的)。

3.3 对齐填充(Padding)

不是必然需要,主要是占位,保证对象大小是某个字节的整数倍。

4 对象的访问定位

使用对象时,通过栈上的 reference 数据来操作堆上的具体对象。

4.1 通过句柄访问

堆中需要有一块叫做“句柄池”的内存空间,句柄中包含了对象实例数据与类型数据各自的具体地址信息。
引用类型的变量存放的是该对象的句柄地址(reference)。访问对象时,首先需要通过引用类型的变量找到该对象的句柄,然后根据句柄中对象的地址找到对象。

在这里插入图片描述

4.2 使用指针访问

引用类型的变量直接存放对象的地址,从而不需要句柄池,通过引用能够直接访问对象。但对象所在的内存空间需要额外的策略存储对象所属的类信息的地址。
在这里插入图片描述


完毕