JAVA面试-JVM篇 08-对象在内存中的布局包含哪些部分
·
JAVA面试-JVM篇 08-对象在内存中的布局包含哪些部分
概述
Java 对象在堆内存中由对象头(Header)、实例数据(Instance Data) 和对齐填充(Padding) 三部分组成。其中对象头又细分为 Mark Word 和 类型指针(Klass Pointer)。理解对象内存布局是分析 JVM 内存占用、锁升级机制、GC 行为的基础。
整体布局
三大部分详解
| 组成部分 | 必选/可选 | 作用 |
|---|---|---|
| 对象头 — Mark Word | 必选 | 存储哈希码、GC 分代年龄、锁状态标志、偏向线程ID 等运行时数据 |
| 对象头 — 类型指针 | 必选 | 指向方法区中该类的元数据(开启指针压缩后 32 位) |
| 实例数据 | 必选 | 对象实际存储的字段值,包括父类继承的字段 |
| 对齐填充 | 可选 | 填充至 8 字节的整数倍,仅当对象大小不是 8 的倍数时存在 |
Mark Word 结构(64位JVM)
Mark Word 是一个动态复用的数据结构,在不同锁状态下存储不同内容:
各状态 Mark Word 位分布
| 锁状态 | 锁标志位 | 存储内容 |
|---|---|---|
| 无锁 | 01 | 25位对象哈希码 + 4位分代年龄 + 1位偏向锁(0) |
| 偏向锁 | 01 | 23位偏向线程ID + 2位Epoch + 4位分代年龄 + 1位偏向锁(1) |
| 轻量级锁 | 00 | 30位指向栈中锁记录的指针 |
| 重量级锁 | 10 | 30位指向重量级监视器(Monitor)的指针 |
| GC 标记 | 11 | 30位GC 转发指针 |
字段重排序(Field Reordering)
- JVM 会按字段字节大小重新排序,将同大小的字段排列在一起,减少内存碎片
- 父类定义的字段优先于子类字段存放
- 子类较宽的字段可能插入到父类的对齐间隙中(仅限 64 位 JVM 且未开启压缩指针时)
内存大小计算示例
假设一个对象有 1 个 int 和 1 个 byte 字段:
| 组件 | 大小(压缩OOPs) |
|---|---|
| Mark Word | 8 B |
| Klass Pointer | 4 B |
| int 字段 | 4 B |
| byte 字段 | 1 B |
| 填充 | 7 B |
| 合计 | 24 B |
总结
- 对象由对象头 + 实例数据 + 对齐填充三部分组成
- Mark Word 在不同锁状态下复用存储空间,是锁升级和 GC 的基础
- JVM 自动字段重排序优化内存布局,减少填充浪费
- 开启压缩指针(-XX:+UseCompressedOops) 可显著减少对象头中类型指针和引用类型字段的大小
更多推荐
所有评论(0)