optional对象在启用压缩指针的jvm中占16字节:对象头12字节(mark word 8字节 + klass pointer 4字节),实例字段value占4字节,无填充,严格遵循8字节对齐规则。

Optional 本身不特殊,它就是一个普通 Java 对象,底层内存布局完全遵循 HotSpot 的通用规则。想看清它的物理结构,关键不是“Optional 有什么特别”,而是看清楚它作为 一个带字段的不可变容器类 在开启指针压缩的默认 JVM 下怎么被分配和对齐。
对象头固定占用 12 字节(64 位 + 压缩指针)
在当前主流 JDK(8u292+、11、17、21)默认配置下,64 位 JVM 启用 -XX:+UseCompressedOops(堆 ≤32GB 时自动开启),Optional 的对象头由两部分组成:
- Mark Word:8 字节 —— 存储 hashCode(首次调用后才写入)、GC 分代年龄(初始为 0)、锁状态(通常为无锁 01)、是否偏向等,动态复用同一块空间
-
Klass Pointer:4 字节 —— 指向元空间中
java.util.Optional类的Klass元数据,不是指向实例数据,也不存任何业务逻辑
二者合计 12 字节,不是 16 字节 —— 这是很多资料未区分压缩开关导致的常见误解。
实例数据只含一个引用字段:value
Optional 的源码极简:private final T value;。无论你传入 Integer、String 还是 null,这个字段在对象内部始终是一个引用类型:
- 在开启压缩指针时,value 占 4 字节
- 它不存储实际值(比如 int 的 4 字节或 String 的字符数组),只存堆中另一个对象的地址(或 null)
- 没有其他字段(无 size、no index、no flags),也没有父类字段可继承(Optional 直接继承 Object)
所以实例数据区总大小 = 4 字节。
对齐填充让总大小变成 16 字节
JVM 要求每个对象起始地址必须是 8 字节对齐,且整个对象大小也需是 8 的倍数。目前累计:对象头 12 字节 + 实例数据 4 字节 = 16 字节,刚好满足 8 字节对齐要求。
- 因此
new Optional(null)或Optional.of("x")在内存中都占 16 字节 - 没有填充字节(padding = 0),但这是计算出来的结果,不是省略——对齐规则仍全程生效
- 对比
new Object():同样 12 + 0 + 4 = 16 字节,Optional 并未额外“膨胀”
验证方式:用 JOL 看真实布局
引入 jol-core:0.17(适配 JDK 21),直接打印:
System.out.println(ClassLayout.parseInstance(Optional.empty()).toPrintable()); // 输出类似: // java.util.Optional object internals: // OFFSET SIZE TYPE DESCRIPTION VALUE // 0 4 (object header) ... // 4 4 (object header) ... // 8 4 (object header) ... // 12 4 Object Optional.value null // 16 8 (loss due to the next object alignment)
注意:OFFSET 0–11 是 Mark Word(跨 3 行显示,因每行 4 字节),OFFSET 12 是 value 字段;最后一行 “loss” 是下一个对象的对齐预留,不属于本对象——这印证了本对象共占 16 字节。











