java对象在jvm堆内存中严格遵循三段式结构:对象头(含mark word、klass pointer、数组长度)、实例数据(字段按类型大小重排序存放)、对齐填充(补至8字节倍数)。

对象头:运行时元信息的容器
对象头是每个 Java 对象必有的头部信息,包含两类核心内容:
- Mark Word(标记字):64 位 JVM 默认占 8 字节,存储哈希码(延迟计算)、GC 分代年龄(4 位)、锁状态标志(2 位)、偏向线程 ID 等。内容随锁升级动态变化——无锁时存哈希与年龄,偏向锁时存线程 ID,重量级锁时存 Monitor 指针。
-
Klass Pointer(类型指针):指向类元数据(即 Class 对象)的地址。开启压缩指针(
-XX:+UseCompressedOops,默认开启)时占 4 字节;关闭后为 8 字节。
数组对象额外多出 4 字节的 Array Length。因此,普通对象头常见大小为 12 字节(8+4),数组对象为 16 字节(8+4+4)。
实例数据:字段值的实际存放区
这部分保存所有成员变量,包括父类继承的字段。JVM 不按源码声明顺序排列,而是按字段类型大小重排序,优先放置大字段以减少空间浪费:
- long / double(8 字节)→ int / float(4 字节)→ short / char(2 字节)→ byte / boolean(1 字节)→ reference(引用,4 或 8 字节)
- 例如:
class Student { int id; String name; boolean gender; }中,name(引用)会排在id后,gender排最后,避免因小字段插在中间导致跨缓存行或额外填充。 - 引用字段大小取决于是否启用压缩指针:开启为 4 字节,关闭为 8 字节。
对齐填充:确保总大小是 8 字节整数倍
HotSpot 要求每个对象起始地址和总大小都必须是 8 的倍数,这是硬性规则,目的有二:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 适配 CPU 缓存行(通常 64 字节 = 8×8 字节),避免伪共享(False Sharing);
- 简化内存管理(如指针碰撞分配)。
填充本身无语义,纯占位。比如一个只有 byte b 的对象:
- 对象头:12 字节(64 位 + 压缩指针)
- 实例数据:1 字节
- 合计 13 字节 → 补 3 字节填充 → 总大小为 16 字节(2×8)
实际空间占用怎么看
不要靠手算,用工具验证最可靠:
- 引入 JOL(Java Object Layout)库:
org.openjdk.jol:jol-core - 代码示例:
System.out.println(ClassLayout.parseInstance(new Student()).toPrintable()); - 输出会清晰列出各字段偏移、大小、填充位置,甚至区分 VM 内部字段。
字段顺序、是否开启压缩指针、继承深度都会影响最终大小——优化时优先把 long、引用等大字段前置,小字段集中排尾,能显著减少填充字节数。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










