一个普通Java对象在堆内存中分为对象头、实例数据和对齐填充三部分;对象头含Mark Word(8字节,动态复用)和Klass Pointer(默认压缩为4字节),实例数据按字段宽度排序存储,对齐填充补足8字节倍数。

Java中一个空的Object对象在堆内存中并非“什么都没有”,而是有明确、紧凑且状态可变的布局结构。核心在于对象头(Header),它由Mark Word和Klass Pointer组成,二者共同支撑JVM的锁机制、GC年龄管理、哈希码生成等关键行为。
对象头的两大部分:Mark Word与类型指针
在64位HotSpot JVM(默认开启指针压缩)下,对象头共占12字节:
- Mark Word:8字节(64 bit) —— 动态复用的空间,内容随对象状态实时切换;
- Klass Pointer:4字节 —— 指向方法区中该类的元数据(Class对象),用于类型判断和方法分派;
若关闭指针压缩(-XX:-UseCompressedClassPointers),Klass Pointer升为8字节,对象头变为16字节。无论哪种配置,JVM都会通过对齐填充将整个对象大小补到8字节的整数倍(例如空Object补4字节,最终占16字节)。
Mark Word的动态结构与锁状态映射
Mark Word不是固定含义的字段,而是一块按位组织的“状态寄存器”。最后3位(lock + biased_lock)决定整体解读方式:
立即学习“Java免费学习笔记(深入)”;
-
无锁态(01):存储identity hashcode(31位)、GC分代年龄(4位)、保留位等;hashcode首次调用
System.identityHashCode()才写入,此前为0; - 偏向锁(101):记录偏向线程ID(54位)、epoch(2位)、年龄(4位),表示“这个锁默认属于某线程”;
- 轻量级锁(00):存指向当前线程栈帧中Lock Record的指针(62位),用于CAS竞争;
- 重量级锁(10):存指向Monitor对象的指针(62位),进入操作系统互斥;
- GC标记态(11):用于三色标记等垃圾回收过程,此时其他字段无效。
这种复用设计让8字节承载多种运行时语义,是JVM内存效率的关键体现。
实例数据与字段排列规则
空Object没有实例字段,所以这部分为0字节。但一旦定义成员变量,其布局受以下规则影响:
- 字段按宽度从大到小排序:
long/double→int/float→short/char→byte/boolean; - 父类字段优先于子类字段;
- 开启
-XX:+CompactFields(默认true)时,窄字段可能插入父类字段间的空隙,减少总体占用; - 每个字段起始地址需满足自身对齐要求(如
long需8字节对齐)。
为什么对齐填充不可省略
CPU访问内存时,对齐读取比非对齐快得多。HotSpot强制对象总长度为8字节倍数,既提升性能,也简化内存管理。例如:
- 空
Object:对象头12字节 → 补4字节 → 总16字节; - 含一个
int字段的类:头12字节 + 数据4字节 = 16字节 → 无需填充; - 含一个
byte字段的类:头12字节 + 数据1字节 = 13字节 → 补3字节 → 总16字节。
这个填充发生在实例数据之后、对象末尾,不参与逻辑,仅服务硬件与内存分配器。


















