昨天,看到有网友留言说没找到 OpenJDK 的 25.0.3 版本,当时身边没电脑就没有立即回复。
今天抽空访问了 openjdk.org,列出的 OpenJDK Release 25.0.3 确确实实在那里,估计是位置没找对。随手又扫了一眼 JDK 27 的进度,发现它准备将 JEP 534: Compact Object Headers by Default 纳入需求清单。
这个特性是不是有点熟悉?没错,就是前几天聊携程踩坑的那篇文章里提到的“紧凑对象头”。现在它要在 JDK 27 中默认开启了,对于 Java 或 JVM 内存优化而言,这算得上一座里程碑。

JDK 27 计划于 2026 年 9 月 14 日发布,JEP 534 是其中一项看起来“低调”却影响深远的特性——紧凑对象头即将成为默认行为。从 JDK 27 开始,Java 应用的内存占用会自动下降、GC 压力会自动减轻,而这一切不需要修改一行业务代码。
JEP 534 是什么?
JEP 534 的全称是 Compact Object Headers by Default,也就是将紧凑对象头设为 HotSpot JVM 的默认对象头布局。
在 64 位架构上,传统 Java 对象头占用 96 bits(12 字节),由两部分组成:
Mark Word(64 bits):存储锁状态、GC 分代年龄、身份哈希码等
Class Pointer(32 bits):指向类的元数据(Compressed Class Pointers)
而 JEP 534 把这一布局压缩到 64 bits(8 字节),通过将类指针嵌入 Mark Word 的未使用位,直接削减了 33% 的对象头开销。
目前 JEP 534 的状态是 #Proposed to Target(已提议纳入),预计 2026 年 5 月 19 日完成评审。但从 JDK 27 官方特性列表来看,它已被列为三个“Proposed to Target”的 JEP 之一,几乎可以确定会进入 JDK 27。理由有三点。
状态明确指向 JDK 27
根据 OpenJDK 官方页面,JEP 534 的 Release 字段明确标注为 27,状态为 Proposed to Target(已提议纳入目标版本),这是进入 JDK 的倒数第二步。
经过了充分的渐进式验证
JEP 534 并非凭空冒出,它走过了完整的“孵化 → 实验 → 正式 → 默认”四步策略:
JDK 24(JEP 450):作为实验特性首次引入,需手动开启
JDK 25(JEP 519):升级为正式产品特性,但仍需 -XX:+UseCompactObjectHeaders 手动开启
JDK 27(JEP 534):设为默认,无需参数自动生效
这种渐进式推进,是 OpenJDK 对核心 JVM 特性一贯的谨慎做法。
大厂生产环境已背书
Amazon:已将紧凑对象头回移植到 JDK 17 和 JDK 21,在数百个生产服务中运行,实测 CPU 降低最高达 30%
SAP:在其发行版 SapMachine 中已默认开启紧凑对象头,每日运行大量测试套件
Oracle:通过了完整的 JDK 测试套件验证
正是这些国外大厂的背书,携程也开始在生产环境灰度替换,这才有了前述的 bug 坑。这里就不展开,详情可以回看上次那篇关于 G1GC 静默数据损坏的文章。
更何况,JEP 534 的 Motivation 章节写得很直接:It is time to make compact object headers the default mode.,是时候让紧凑对象头成为默认模式了。
这个特性要解决什么问题?
说起来有些无奈,其他语言的一些程序员总爱攻击 Java 是内存开销大户。这可能是 Java 历史上最大的黑标签之一,但现在的 Java 早已不是当年的“阿斗”。不管怎么黑,都撼动不了 Java 的伟大。
Java 对象头的隐性税
Java 开发者都知道“一切皆对象”,但很多人没意识到,每个对象都在为“头信息”支付沉重的内存税。在现代 Java 应用中:
- 对象头占堆内存的
20% 以上
- 对于 32~64 字节的小对象,12 字节的头意味着
37.5% 的额外开销
- 微服务、Spring Boot、JSON 解析、集合类密集等场景,对象数量动辄千万级,这部分开销被急剧放大
更隐蔽的问题是 缓存局部性(Cache Locality):对象越大,能塞进 CPU L1/L2 缓存的对象就越少,导致更多的主内存访问,性能在无形中被“偷走”。这也是为什么该特性一推出就受到大厂追捧并在生产环境落地的原因之一,因为它确实能硬碰硬地降低硬件成本。
快递包裹的填充物
可以这样想:你采购了 100 个手机壳,每个手机壳(对象数据)本身很小,但每个都用一个大纸箱(对象头)包装。纸箱占了一半体积,运输成本(内存/CPU)自然就高了。JEP 534 干的事就是“换成小纸箱”。大商家发货量一大,一年省下的成本至少十几万起步。
带来哪些好处?
综合社区反馈,至少有四个显著收益。
堆内存显著降低
| 测试场景 |
收益 |
| SPECjbb2015 |
堆内存减少 22% |
| 10M 个 Point 对象基准测试 |
提交内存减少 30%,使用内存减少 12% |
CPU 使用率下降
| 测试场景 |
收益 |
| SPECjbb2015 |
CPU 时间减少 8% |
| Amazon 生产环境 |
最高 30% CPU 降低 |
| 高并发 JSON 解析 |
执行时间减少 10% |
GC 压力减轻
- SPECjbb2015 的 GC 次数减少
15%(G1 和 Parallel GC 均适用)
- 更少的对象头意味着更少的堆扫描工作量,GC 停顿更短、更稳定
云原生部署密度提升
- 容器内存需求降低 → 单机可部署更多实例
- 冷启动更快(内存分配减少)
- 直接转化为
云成本节省
正如一些知名国外程序员所言,这些改进在成本敏感的环境中尤其有价值,因为内存效率能直接转化为运营节省。
技术原理
4 字节是怎么省出来的?先看传统对象头布局:
┌────────────────────────────────────────┬────────────────────┐
│ Mark Word (64 bits) │ Class Pointer (32) │
│ 锁状态 | GC 年龄 | 哈希码 | 其他元数据 │ 指向类元数据地址 │
└────────────────────────────────────────┴────────────────────┘
12 字节 (96 bits) 总计
再看紧凑对象头布局:
┌────────────────────────────────────────────────────────────┐
│ 合并后的 64-bit 头 │
│ 锁状态 | GC 年龄 | 哈希码(31bit) | 类指针(22bit) | 其他 │
└────────────────────────────────────────────────────────────┘
8 字节 (64 bits) 总计
核心技巧如下:
- 类指针压缩:从 32-bit 压缩到
22-bit,支持约 400 万个唯一类,远超任何真实应用需求
- 嵌入 Mark Word:将压缩后的类指针直接嵌入 Mark Word 的未使用位,消除独立的 Class Pointer 字段
- 保留 31-bit 哈希码:为避免哈希碰撞影响大哈希表性能,身份哈希码仍保留 31 位
会不会影响锁机制的兼容性?答案是不会。因为 Project Lilliput 在 JDK 22 引入了 Object Monitor Tables 基础设施,解决了 64-bit 头无法存储完整锁指针的问题,确保同步语义不受影响。
对开发者意味着什么?
先看用法。
在 JDK 27 之前(JDK 25/26),需要手动开启:
java -XX:+UseCompactObjectHeaders -jar app.jar
在 JDK 27 及之后,默认开启,无需任何操作。
若因特殊原因需要回退到旧布局(例如某些依赖旧对象头布局的 JNI/Unsafe 代码),可用下面的参数显式关闭:
java -XX:-UseCompactObjectHeaders -jar app.jar
同时需要知道,超过 95% 的中小企业(尤其国内用户),很多非默认特性并不会主动开启。有的是对新特性不熟悉,有的是 JDK 版本长期不升级,还有的觉得预期收益不如大厂明显。但现在好了,JDK 27 直接默认。
再来看注意事项:
- 不能与
-XX:-UseCompressedClassPointers 同时使用(该参数已废弃)
- x64 上的 ZGC 支持仍在完善中(但 G1、Parallel、Shenandoah 已完全支持)
- 类数量上限约 400 万,对 99.9% 的应用不构成限制
Project Lilliput
JEP 534 是 Project Lilliput 的阶段性成果,一场历时三年的“瘦身”工程。该项目由 Red Hat 的 Roman Kennke 于 2021 年发起,目标是将 Java 对象头从 128 bits 一步步压缩到 64 bits,最终甚至到 32 bits。
| 阶段 |
JDK 版本 |
里程碑 |
| 基础设施 |
JDK 22 |
引入 Object Monitor Tables |
| 实验阶段 |
JDK 24 |
JEP 450 实验性紧凑对象头 |
| 正式产品 |
JDK 25 |
JEP 519 正式集成,手动开启 |
| 默认开启 |
JDK 27 |
JEP 534 设为默认 |
| 未来目标 |
TBD |
Lilliput 2,32-bit 对象头 |
也就是说,紧凑对象头的压缩还远没到终点。
很多优秀特性的背后都有大厂推动,JEP 534 也不例外。Amazon 工程团队表示,将紧凑对象头回移植到 JDK 17 和 JDK 21 后,在数百个生产服务中验证了稳定性和性能收益,这种现实世界的验证影响了将特性集成到 JDK 25 的决定。SAP 的 SapMachine 更是“抢先一步”默认开启紧凑对象头,每天运行大量客户场景测试,为社区提供了宝贵的兼容性数据。这也是 JDK 27 将其设为默认的最重要原因之一。
总结
JEP 534 或许是 JDK 27 中最“润物细无声”的特性之一,却是一次“零成本”的性能跃升:
- 无需改代码,纯 JVM 层优化
- 无需调参数,JDK 27 默认生效
- 内存降低 20%+,堆更省、GC 更少
- CPU 降低 8-30%,缓存更高效、计算更省
- 云成本直接节省,容器密度提升、资源利用率更高
可能有人会觉得,只是改了一个“默认”开启而已,但背后却能影响无数后续升级到 JDK 29 等 LTS 版本的中小企业用户,受益的是整个 Java 生态。
对于运行在云原生环境、微服务架构、内存敏感型应用中的 Java 开发者来说,JDK 27 的这次升级,堪称 免费午餐。正如 JEP 534 所言,We intend to deprecate the old object header layout in a future release.,紧凑对象头就是 Java 对象内存布局的未来。非常期待 Lilliput 项目继续推进,早日落地“32 bit 对象头”。
本文由云栈社区整理发布。欢迎访问 云栈社区 与众多开发者交流技术。
参考资料
- JEP 534: Compact Object Headers by Default
https://openjdk.org/jeps/534
- JDK 27 Project Page
https://openjdk.org/projects/jdk/27/
- JEP 519: Compact Object Headers
https://openjdk.org/jeps/519