普通Java对象在堆内存中由对象头、实例数据、对齐填充三部分组成;对象头含Mark Word(8字节)和Class Pointer(4字节,压缩指针下),数组对象头多4字节长度字段;实例数据按宽度降序排列并紧凑存储;对齐填充确保对象总大小为8字节整数倍。

普通Java对象在堆内存中由三部分组成:对象头、实例数据、对齐填充。这是HotSpot虚拟机(主流JDK默认)的内存布局,与语言规范无关,但实际开发中理解它有助于分析内存占用、锁优化、GC行为等。
对象头(Object Header)
对象头占12字节(32位JVM下为8字节,但64位+开启指针压缩是常见场景),包含两部分:
- Mark Word(8字节):存储哈希码、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID等。这些信息在运行时动态复用,例如未加锁时存哈希码,加轻量级锁后存指向栈中锁记录的指针,偏向锁时存线程ID。
- Class Pointer(4字节,开启指针压缩):指向该对象所属类的Klass结构(元数据)地址。若关闭指针压缩(-XX:-UseCompressedOops),则为8字节。
注意:数组对象的对象头多出4字节的数组长度字段(int类型),所以数组对象头共16字节(压缩指针下)。
实例数据(Instance Data)
即对象真正存储的成员变量值,按以下顺序排列:
立即学习“Java免费学习笔记(深入)”;
- 父类字段优先于子类字段;
- 相同宽度的字段会紧凑排列(如long/double放一起,int放一起),以减少空间浪费;
- HotSpot默认按 long/double → int/float → short/char → byte/boolean → reference 的降序排列(可通过-XX:FieldsAllocationStyle=1关闭重排序,但不推荐)。
例如:class A { byte b; int i; long l; },字段实际内存顺序是 l(8字节)、i(4字节)、b(1字节),后面再补3字节对齐填充,使整个实例数据块满足8字节对齐要求。
对齐填充(Padding)
不是必然存在,而是为了保证对象总大小是8字节的整数倍(即满足CPU缓存行对齐)。JVM要求每个对象起始地址必须是8字节对齐,因此当对象头+实例数据的总字节数不是8的倍数时,会在末尾自动填充若干字节(0~7字节)。
- 填充只发生在对象末尾,不会插在字段中间;
- 填充字节内容无意义,仅用于占位;
- 可通过JOL(Java Object Layout)工具验证,例如
new Object()在64位+压缩指针下占16字节(12字节对象头 + 4字节填充)。
一个完整例子(64位JDK,-XX:+UseCompressedOops)
考虑如下类:
class Demo {
boolean flag; // 1字节
int x; // 4字节
Object obj; // 4字节(压缩引用)
}
内存布局为:
- 对象头:12字节(Mark Word 8 + Class Pointer 4)
- 实例数据:按策略重排后为
x(4)+ obj(4)+ flag(1)+ padding(3)= 12字节 - 对齐填充:对象头12 + 实例数据12 = 24字节,已是8的倍数,无需额外填充
最终大小:24字节。


















