Java堆中对象的分配、布局和访问

2.3 HotSpot虚拟机对象探秘

2.3.1 对象的创建

当Java虚拟机遇到一条字节码new指令时,首先检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用代表的类是否被加载、解析和初始化过。如果没有,则执行相应的类加载过程。

类加载通过后,VM将为其分配内存,内存大小在类加载完成后便可完全确定,其相当于把一块确定大小内存块从Java堆中划分出来。

内存分配有两种方式:指针碰撞和空闲列表,分别用于连续空间与非连续空间划分。

内存分配完后,VM需要将分配到的内存空间初始化为0值。

然后,VM还需要对对象进行必要的设置,例如这个对象是哪个类的实例,如何才能找到类的元数据信息、对象的哈希码、对象的GC分代年龄等。这些信息存放在对象的对象头中。

做完以上工作后,从VM的角度来看,一个新的对象已经诞生了。但是,从Java程序的角度来看,对象创建才刚刚开始,构造函数,既Class文件中的()方法还没有执行。

2.3.2 对象的内存布局

在HotSpot虚拟机中,对象在堆内存中的存储布局可以划分为三个部分:对象头(header),实例数据(Instance Data)和对齐填充(Padding)。

2.3.3 对象的访问定位

Java程序会通过栈上的reference数据来操作堆上的具体对象。主流的访问方式主要有:

  • 句柄访问:Java堆中可能会划出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,句柄中包含了对象实例数据和类型数据各自具体的地址信息
  • 直接指针访问:Java堆中对象的内存布局就需考虑如何放置访问类型数据的相关信息,reference中存储的直接就是对象地址,如果是访问对象本身,就不需要多一次间接的开销。
作者

bd160jbgm

发布于

2021-05-28

更新于

2021-05-29

许可协议