简述 Java 的对象结构
在 JVM 中,Java 对象在堆内存中的结构通常分为 3 部分:对象头(Object Header)、实例数据(Instance Data)、对齐填充(Padding),部分对象(如数组)会额外包含 “数组长度” 字段,具体结构如下:
# 1. 对象头(Object Header)
对象头是对象的核心标识,占 8 字节(32 位 JVM)或 16 字节(64 位 JVM,默认开启指针压缩后为 12 字节),包含两部分信息:
- (1)Mark Word(标记字段):
- 占 4 字节(32 位)或 8 字节(64 位),存储对象的运行时状态,如哈希码(HashCode)、GC 分代年龄、锁状态标志、线程持有的锁、偏向线程 ID 等;
- 示例(64 位 JVM,无指针压缩):
- 锁状态为 “无锁” 时,Mark Word 存储哈希码(25 位)、GC 年龄(4 位)、锁标志(2 位,01)、偏向锁标志(1 位,0);
- 锁状态为 “偏向锁” 时,Mark Word 存储偏向线程 ID(54 位)、GC 年龄(4 位)、锁标志(2 位,01)、偏向锁标志(1 位,1)。
- (2)Klass Pointer(类型指针):
- 占 4 字节(32 位)或 8 字节(64 位,开启指针压缩后为 4 字节),指向对象对应的类元信息(存储在方法区 / 元空间),用于确定对象的类型(如 “该对象是 User 类的实例”);
- 数组对象的特殊处理:数组对象的对象头额外包含 “数组长度” 字段(4 字节),用于存储数组的元素个数(如
int[] arr = new int[5],数组长度字段值为 5)。
# 2. 实例数据(Instance Data)
- 存储对象的实例字段(包括从父类继承的字段),字段的存储顺序由 JVM 决定(默认按 “long/double → int/float → short/char → byte/boolean → 引用类型” 的顺序排列,可通过
-XX:FieldsAllocationStyle调整); - 字段的内存占用与类型相关:
byte占 1 字节、short占 2 字节、int占 4 字节、long占 8 字节、对象引用占 4 字节(64 位 JVM 开启指针压缩)或 8 字节(未开启)。
# 3. 对齐填充(Padding)
- 作用:确保对象的总大小是 8 字节的整数倍(JVM 的内存分配单位是 8 字节),提升内存访问效率(CPU 按 8 字节块读取内存,对齐后减少读取次数);
- 示例:若对象头(12 字节)+ 实例数据(4 字节)= 16 字节(8 的整数倍),无需填充;若实例数据为 5 字节,则填充 3 字节,使总大小为 24 字节。
上次更新: 12/30/2025