Java 对象内存布局分析
在 HotSpot 虚拟机中,Java 对象的内存布局由三部分组成:对象头(Header)、实例数据(Instance Data) 和 对齐填充(Padding)。其中对象头包含 Mark Word 和 Klass Pointer,具体占比取决于系统架构和 JVM 配置(以 64 位系统为例):
1. 对象头 (Header)
- Mark Word(8 字节)
存储对象运行时数据:
$$ \text{哈希码} + \text{GC 年龄} + \text{锁状态} + \text{偏向信息} $$ - Klass Pointer(4 字节)
指向类元数据的指针(开启指针压缩时):
$$ \text{KlassPtr} \rightarrow \text{方法区中的类结构} $$
2. 实例数据 (Instance Data)
存储对象字段值,大小由字段类型决定:
- 基本类型:$ \text{int} = 4\text{B}, \text{long} = 8\text{B} $
- 引用类型:$ 4\text{B} $(指针压缩时)
3. 对齐填充 (Padding)
确保对象总大小为 8 字节的整数倍,满足 CPU 内存对齐要求。
占比计算(64 位系统 + 指针压缩)
假设对象含以下字段:
class Example {
int a; // 4B
long b; // 8B
String c; // 4B (引用)
}
| 组件 | 大小计算 | 实际大小 | 总占比 |
|---|---|---|---|
| 对象头 | Mark Word + Klass Ptr | 12B | 33.3% |
| 实例数据 | $4 + 8 + 4$ | 16B | 44.4% |
| 对齐填充 | 补足 $12+16=28$ → 32 | 4B | 11.1% |
| 总计 | - | 32B | 100% |
$$ \text{总大小} = 32\text{B} \quad \left( \frac{\text{对象头}}{32} \times 100% \approx 37.5% \right) $$
关键影响因素
-
指针压缩(
-XX:+UseCompressedOops)- 开启时:Klass Pointer = 4B,引用 = 4B
- 关闭时:Klass Pointer = 8B,引用 = 8B
(关闭后对象头占比升至 ≈50%)
-
字段类型优化
字段重排序可减少内存间隙:// 优化前:int(4) + long(8) → 可能产生4B间隙 // 优化后:long(8) + int(4) → 无间隙 -
对象对齐规则
内存分配满足 $ \text{size} \mod 8 = 0 $,否则自动填充。
验证代码
使用 JOL 工具查看实际布局:
// 添加依赖:org.openjdk.jol:jol-core
public static void main(String[] args) {
System.out.println(ClassLayout.parseClass(Example.class).toPrintable());
}
输出示例:
Example object internals:
OFFSET SIZE TYPE DESCRIPTION
0 12 (object header) // Mark+Klass
12 4 int Example.a
16 8 long Example.b
24 4 String Example.c
28 4 (alignment) // Padding
验证总大小:$12 + 4 + 8 + 4 + 4 = 32\text{B}$
170万+

被折叠的 条评论
为什么被折叠?



