前言
在HotSpot虚拟机中,对象在内存中存储的布局分为3块区域:
- 对象头
- 实例数据
- 对其填充
对象头
对象头中包括两部分信息:
- 第一部分用于存储对象自身的运行时数据,长度为32位或64位:
- 哈希码
- GC分代年龄
- 锁状态标志
- 线程持有的锁
- 偏向线程ID
- 偏向时间戳
因为对象头占用的空间比较小,所以空间不是固定的数据结构,是随着状态不同,而存储的内容不同:
存储内容 | 标志位 | 状态 |
指向栈中锁记录的指针 | 00 | 轻量级锁 |
对象哈希码、对象分代年龄 | 01 | 未锁定 |
偏向线程ID、偏向时间戳、对象分代年龄 | 01 | 可偏向锁 |
指向重量级锁的指针 | 10 | 重量级锁 |
空,不需要记录信息 | 11 | GC标记 |
- 第二部分是类型指针,
- 就是对象指向它的类元数据的指针。
- 如果对象是Java数组,在对象头中还必须有一块用于记录数组长度的数据。
- 因为数组的元数据中无法确定数组的大小。但是虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小。
实例数据
存储对象的有效信息,也就是在代码中定义的各种类型的字段。
无论是从父类继承下来的,还是在子类中定义的字段。
相同宽度的字段总是被分配到一起。
在满足这个前提的条件下,在父类中定义的变量会出现在子类之前。
当CompactFields参数值为true,那么子类之中较窄的变量也可能会插入到父类变量的空隙之中。
对齐填充
对齐填充不是必然存在的,仅仅起着占位符的作用。
HotSpot的自动内存管理系统要求对象的起始地址必须是8字节的整数倍。