Java对象头是嵌入对象起始位置的动态元数据区,由8字节Mark Word和4/8字节Klass Pointer构成,总长12/16字节(数组+4字节长度),紧邻实例数据且参与8字节对齐。

Java 中类与对象的对象头在底层内存中不是固定不变的“模板”,而是随 JVM 配置、对象状态和类型动态组织的紧凑结构。它不单独存在,而是嵌入在每个对象实例的起始位置,是 JVM 运行时管理对象的核心元数据区。
对象头由 Mark Word 和 Klass Pointer 构成
在 HotSpot JVM(主流实现)中,对象头严格分为两个逻辑部分:
- Mark Word:固定 8 字节(64 位 JVM),存储运行时动态信息。内容会根据锁状态、是否计算过 hashCode、GC 分代年龄等实时切换格式。例如无锁时存哈希码(31 位)+ 年龄(4 位)+ 锁标志(2 位);轻量级锁时则存指向栈中锁记录的指针。
-
Klass Pointer:指向该对象所属类的元数据(Klass 结构)。大小取决于是否启用压缩指针:
– 开启-XX:+UseCompressedOops(默认,堆 ≤ 32GB)→ 占 4 字节
– 关闭或堆 > 32GB → 占 8 字节
因此,普通对象头在 64 位 + 压缩指针下为 12 字节(8 + 4);未压缩则为 16 字节(8 + 8)。数组对象额外多 4 字节存储数组长度,头大小变为 16 或 20 字节。
对象头紧贴实例数据前,不独立分配
对象头不是单独申请的一块内存,而是对象整体布局的第一段。一个新创建的 new Object() 在堆中内存布局如下:
- 地址偏移 0~11:12 字节对象头(Mark Word 8B + Klass Pointer 4B)
- 其后紧跟实例字段(本例为空)
- 最后按需填充至 8 字节对齐(12 字节 + 0 字段 = 12,需补 4 字节 → 总大小 16 字节)
也就是说,对象头的地址就是整个对象的起始地址,JVM 通过这个地址直接读取前若干字节解析锁状态或类型信息。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
类本身没有“对象头”,但有对应的 Klass 元数据
注意:“类”在 JVM 中不是 Java 对象(不继承自 Object),不会被实例化为堆中对象,因此没有传统意义上的对象头。但 HotSpot 内部为每个加载的类维护一个 C++ 层的 Klass 结构(位于元空间),其中包含 vtable、ITable、静态字段、方法元信息等。这个 Klass 结构有自己的内存布局,但它不叫“对象头”,也不参与 Java 对象的三段式布局。
而你代码中写的 MyClass.class 是一个 java.lang.Class 实例——它本身是一个 Java 对象,所以它有标准的对象头(12 字节)、实例数据(如 name、loader 等字段)和对齐填充。
对齐填充影响对象头“可见边界”
JVM 要求每个对象总大小必须是 8 字节的整数倍,这是为了 CPU 高效访问内存(避免跨缓存行读取)。对象头作为开头部分,其结束位置不决定对齐点;真正决定是否需要填充的是「对象头 + 实例数据」的总和。
- 例如:对象头 12B + 一个
long字段(8B)= 20B → 向上对齐到 24B,补 4 字节填充 - 再加一个
int(4B)→ 12 + 8 + 4 = 24B → 刚好对齐,无需填充
填充字节位于实例数据之后、对象末尾之前,不属于对象头,也不携带任何语义,仅作地址对齐用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










