JVM学习笔记->对象的内存布局

在HotSpot虚拟机中,对象在内存中存储的布局可以分为3个区域:对象头(Header)、示例数据(Instance Data)、对其填充(Padding)

对象头(Header)

HotSpot 虚拟机的对象头包括两部分(非数组对象)信息,如下图所示:
JVM学习笔记->对象的内存布局

  • 第一部分用于存储对象自身的运行时数据,如哈希码(HashCode)、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳、对象分代年龄,这部分信息称为“Mark Word”;Mark Word 被设计成一个非固定的数据结构以便在极小的空间内存储尽量多的信息,它会根据自己的状态复用自己的存储空间。
  • 第二部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例;
  • 如果对象是一个 Java 数组,那在对象头中还必须有一块用于记录数组长度的数据。因为虚拟机可以通过普通 Java 对象的元数据信息确定 Java 对象的大小,但是从数组的元数据中无法确定数组的大小。

这部分数据的长度在 32 位和 64 位的虚拟机(未开启压缩指针)中分别为 32bit 和 64bit。

例如,在 32 位的 HotSpot 虚拟机中,如果对象处于未被锁定的状态下,那么 Mark Word 的 32bit 空间中的 25bit 用于存储对象哈希码,4bit 用于存储对象分代年龄,2bit 用于存储锁标志位,1bit 固定为 0,如下表所示:
JVM学习笔记->对象的内存布局
在 32 位系统下,存放 Class 指针的空间大小是 4 字节,Mark Word 空间大小也是4字节,因此头部就是 8 字节,如果是数组就需要再加 4 字节表示数组的长度,如下表所示:
JVM学习笔记->对象的内存布局在 64 位系统及 64 位 JVM 下,开启指针压缩,那么头部存放 Class 指针的空间大小还是4字节,而 Mark Word 区域会变大,变成 8 字节,也就是头部最少为 12 字节,如下表所示:
JVM学习笔记->对象的内存布局
压缩指针:开启指针压缩使用算法开销带来内存节约,Java 对象都是以 8 字节对齐的,也就是以 8 字节为内存访问的基本单元,那么在地理处理上,就有 3 个位是空闲的,这 3 个位可以用来虚拟,利用 32 位的地址指针原本最多只能寻址 4GB,但是加上 3 个位的 8 种内部运算,就可以变化出 32GB 的寻址。

实例数据(Instance Data)

实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。

这部分的存储顺序会受到虚拟机分配策略参数和字段在 Java 源码中定义顺序的影响。

对齐填充(Padding)

对齐填充不是必然存在的,没有特别的含义,它仅起到占位符的作用。

由于 HotSpot VM 的自动内存管理系统要求对象起始地址必须是 8 字节的整数倍,也就是说对象的大小必须是 8 字节的整数倍。对象头部分是 8 字节的倍数,所以当对象实例数据部分没有对齐时,就需要通过对齐填充来补全。