Java 对象内存布局详解
Java 对象内存布局详解
Java 对象在内存中的存储布局可分为三个主要部分:对象头(Header)、实例数据(Instance Data) 和对齐填充(Padding)。其中对象头是理解 JVM 中对象存储机制的关键。
一、对象头(Object Header)
对象头包括两类信息:Mark Word 和类型指针(Class Pointer),如果对象是数组,则还包含数组长度。
1.1 Mark Word
用于存储对象自身的运行时数据,长度在 64 位 JVM 中为 8 字节,主要包括:
哈希码(hashCode)
GC 分代年龄
锁状态标志(如偏向锁、轻量级锁、重量级锁)
线程持有的锁
偏向线程 ID
偏向时间戳等
这些信息并非同时全部存在,而是根据对象状态复用了同一块存储空间,以节省内存。
1.2 类型指针(Class Pointer)
即指向对象类元数据的指针,JVM 通过该指针确定对象属于哪个类。
在 64 位 JVM 中,不开启压缩时为 8 字节,开启压缩(
-XX:+UseCompressedClassPointers
,默认开启)后为 4 字节。可使用命令
java -XX:+PrintCommandLineFlags -version
查看是否开启类指针压缩。
注意:32 位 JVM 中类型指针长度为 4 字节,但如今主流环境已普遍使用 64 位 JVM。
1.3 数组长度(仅数组对象有)
如果对象是数组,对象头中还会有一个额外字段记录数组长度,占 4 字节。
二、实例数据(Instance Data)
存放对象的所有成员变量(字段),包括从父类继承的字段。其所占空间取决于具体字段类型与数量。
基本类型:如
int
占 4 字节,long
占 8 字节等。引用类型:在未开启普通对象指针压缩(
-XX:+UseCompressedOops
,默认开启)时占 8 字节,压缩后为 4 字节。
三、对齐填充(Padding)
由于 HotSpot JVM 要求对象大小必须是 8 字节的整数倍,因此当对象头与实例数据总大小不是 8 的倍数时,会通过对齐填充来补全。这是一种内存对齐手段,旨在提高内存访问效率。
四、示例分析
例1:Object o = new Object()
Mark Word:8 字节
类指针(默认开启压缩):4 字节
实例数据:
Object
无实例字段,因此为 0总大小:8 + 4 = 12 → 不是 8 的倍数,需填充 4 字节
✅ 最终占用:16 字节
若关闭类指针压缩:
类指针为 8 字节,总大小 8 + 8 = 16,无需填充,仍为 16 字节。
例2:User u = new User(1, "张三");
假设 User
类含两个字段:int id
和 String name
。
Mark Word:8 字节
类指针(压缩):4 字节
实例数据:
int id
:4 字节String name
(引用,压缩后):4 字节
小计:8 + 4 + 4 + 4 = 20 → 非 8 的倍数,需填充 4 字节
✅ 最终占用:24 字节
总结
对象内存布局是理解 JVM 内存管理、同步机制和性能优化的基础。具体大小受是否启用指针压缩、字段类型、是否数组等因素影响。若需准确分析对象内存占用,建议使用 JOL(Java Object Layout)工具进行测量。