JVM - 对象的内存布局

2021/07/29 JVM 共 906 字,约 3 分钟
Bob.Zhu

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

  • 对象头
    • 类型指针
    • 运行时数据
  • 实例数据
  • 对齐填充

对象头

HotSpot 虚拟机对象的对象头部分包括两类信息:

  • 第一类是用于存储对象自身的运行时数据,如哈希码(HashCode)、GC 分代年龄、锁状态标志、线程 持有的锁、偏向 线程 ID、偏向时间戳等
  • 对象头的另外一部分是类型指针,即对象指向它的类型元数据的指针,Java 虚拟机通过这个指针来 确定该对象是哪个类的实例。

Mark Word

存储对象自身的运行时数据部分,数据的长度在 32 位和 64 位的虚拟机(未开启压缩指针)中分别为 32 个比特和 64 个比特,官方称它为“Mark Word”。

元数据

并不是所有的虚拟机实现都必须在对象数据上保留类型指针,换句话说,查找对象的元数据信息并不一定要 经过对象本身,这点我们会在下一节具体讨论。此外,如果对象是一个 Java 数组,那在对象头中还必须 有一块用于记录数组长度的数据,因为虚拟机可以通过普通 Java 对象的元数据信息确定 Java 对象的 大小,但是如果数组的长度是不确定的,将无法通过元数据中的信息推断出 数组的大小。

实例数据

实例数据部分是对象真正存储的有效信息,即我们在程序代码里面所定义的 各种类型的字段内容,无论是 从父类继承下来的,还是在子类中定义的字段都必须记录 起来。这部分的存储顺序会受到虚拟机分配策略 参数(-XX:FieldsAllocationStyle 参数)和字段在 Java 源码中定义顺序的影响。

默认的分配策略中,相同宽度的字段总是被分配到一起存放,在满足这个前提条件的情况下,在父类中定义 的变量会出现在子类之前。

对齐填充

对齐填充,这并不是必然存在的,也没有特别的含义,它仅仅起 着占位符的作用。由于 HotSpot 虚拟机 的自动内存管理系统要求对象起始地址必须是 8 字节的整数倍,换句话说就是任何对象的大小都必须是 8 字节的整数倍。对象头部分已经被精心设计成正好是 8 字节的倍数(1 倍或者 2 倍),因此,如果对象 实例数据部分没有对齐的话,就需要通过对齐填充来补全。

参考资料

文档信息

Search

    Table of Contents