Java对象在堆中严格分为对象头、实例数据、对齐填充三部分:对象头含Mark Word(8字节)和Klass Pointer(4或8字节),数组额外加4字节length;实例数据按字段宽度排序存储;对齐填充确保总大小为8的倍数以提升CPU访问效率。

Java对象在堆内存中不是随意堆放的,而是严格按三部分组织:对象头、实例数据、对齐填充。这三者共同决定一个对象实际占多少字节,也直接影响GC行为、缓存局部性和内存浪费程度。
对象头:每个对象的“身份证”
对象头是所有Java对象的固定前缀,不随字段增减而变化,包含两类关键信息:
- Mark Word(8字节):存储哈希码、锁状态(无锁/偏向/轻量级/重量级)、GC分代年龄、是否为偏向锁等。64位JVM下始终占8字节,与是否开启指针压缩无关。
-
Klass Pointer(类指针,4字节):指向方法区中该对象所属类的元数据。仅在开启压缩指针(
-XX:+UseCompressedOops,JDK8+默认开启)时为4字节;关闭后升为8字节。
数组对象额外多出4字节的length字段,所以数组对象头共16字节(8+4+4),普通对象头为12字节(8+4)。
实例数据:字段值的真实落脚点
这部分存放对象声明的所有实例字段,包括从父类继承来的字段。字段排列顺序遵循JVM优化规则:一般按宽度从大到小排序(如long/double → int/float → char/short → byte/boolean),以减少后续对齐填充。但实际顺序还受JVM实现和字段声明顺序影响。
各类型字段占用大小(以开启压缩指针的64位JVM为准):
- boolean / byte:1字节
- char / short:2字节
- int / float:4字节
- long / double:8字节
- 引用类型(如String、Object):4字节(仅为指针,不包含所指对象内容)
注意:String对象本体只含几个字段(如value引用、hash、coder等),它内部引用的字符数组(byte[]或char[])是独立对象,需单独计算内存。
对齐填充:让总大小凑成8的倍数
JVM要求每个对象在堆中占用的总字节数必须是8的整数倍,这是为了CPU高效访问——现代处理器对齐读取更快,且某些指令(如CAS)依赖对齐地址。
计算方式很简单:
对齐填充 = (8 − (对象头字节数 + 实例数据字节数) % 8) % 8
举例说明:
-
new Object():头12B + 数据0B = 12B → 补4B → 总16B -
int id; String name; boolean active;:头12B + (4+4+1)=9B = 21B → 补3B → 总24B -
int[2]:数组头16B + 元素2×4=8B = 24B → 无需填充 → 总24B -
long[2]:数组头16B + 元素2×8=16B = 32B → 无需填充 → 总32B
填充本身不存任何有效数据,纯属空间代价,但能换来显著的访问性能收益。










