JDK 27 刚把 Compact Object Headers 与 G1 的默认布局等「跑时底座」推到更稳的位置;Project Leyden 的下一步则更直接地瞄准启动与预热:把优化后的原生码写进 AOT cache,让生产进程在 HotSpot 启动后即可加载使用。InfoQ 在 2026 年 9 月 21 日当周的 Java 新闻汇总中报道,JEP 544: Ahead-of-Time Code Compilation 已从 Candidate 提升为 Proposed to Target JDK 28(截至 OpenJDK 页面 2026-09-21 更新,仍非 Targeted / 已交付;本文按 Proposed 撰写,切勿当作 GA 特性)。
一句话:训练跑编译,生产跑加载
JEP 544 的核心主张很清晰:在训练跑(training run)里,用与日常 JIT 相同的 C1/C2 管线,把选中的热点方法编译成优化原生码(文中称 AOT code),写入已有的 AOT cache;随后的生产跑在启动时若命中可用缓存,即可立刻拿到这些原生码,从而缩短启动与预热,更快逼近峰值性能。若生产负载漂移,HotSpot 仍可按既有机制去优化、再优化——AOT 与 JIT 代码可共存、可互换,对应用透明。
它明确不是「纯 AOT 模式」:非目标包括关掉解释器/JIT、跨架构交叉编译,以及覆盖 HotSpot 当前支持的全部 CPU。首期目标架构为 AArch64 与 x64。
Leyden 路线上的第三块拼图
Leyden 的思路是把「本可在每次生产跑里当场做」的工作前移到训练跑,再经 AOT cache 复用:
| 能力 | 相关 JEP | 大致落地版本(OpenJDK 叙述) | 往 cache 里塞什么 |
|---|---|---|---|
| 类加载与链接 | JEP 483 | JDK 24 | 已加载、已链接的类形态 |
| 方法剖析 | JEP 515 | JDK 25 | 训练跑采集的执行剖析,便于生产尽早跑 C2 |
| 原生码编译 | JEP 544 | 拟 JDK 28(Proposed) | 训练跑生成的优化原生码 |
因此 544 是在 483/515 之上「补上编译本身」,而不是另起一套工作流:仍扩展现有 AOT cache 创建流程,不要求改业务代码、库或框架,也不强制改 HotSpot 配置(除启用 AOT cache)。Serial / Parallel / G1 / ZGC 均在目标支持范围内。
能力边界:cache 里有什么、用时要注意什么
有什么。 在启用 AOT code 之后,同一份 AOT cache 除了预链接类与剖析数据外,还会默认包含为部分热点方法生成的 AOT code。生产侧若请求某方法的优化码且缓存命中且约束满足,即可即时加载;否则回退解释器与 JIT。
没有什么 / 不做的事。
- 不承诺「训练一次、任意环境通用」:训练与生产需本质相似(JEP 483 已述);若 cache 含 AOT code,还须 同一 CPU 架构与相同 CPU 特性(例如带 AVX-512 的 x64 码不能在无该特性的 x64 上跑),以及 相同垃圾收集器(AOT code 含 GC 相关读写屏障)。不满足时 HotSpot 会告警并不加载 AOT code,但仍可使用 cache 中的类与剖析信息。
- 不做交叉编译;不做「只跑 AOT、永不 JIT」。
- AOT code 与 JIT code 可以不同:例如类初始化次序、
static final在训练时尚不可当编译期常量等,C2 会生成慢/快路径或显式加载字段的版本;峰值仍可由后续 JIT 接力。
与现有 CDS / AOT 的关系。 544 明确是「扩展既有 AOT cache 创建工作流」,而不是引入全新 CDS 替代方案。应用侧仍以 -XX:AOTCacheOutput=... 做训练、-XX:AOTCache=... 做生产为主路径;也可用 AOTMode=record|create 与 AOTConfiguration 分步。诊断开关如 AOTCodeCaching、AOTMode=required、PrintCompilation 等见 JEP 正文。
下列命令摘自 JEP 544 示例,以 JEP / 发行版
java手册为准,本文未本地验证(当前也尚非 JDK 28 GA):# 训练:写出含 AOT code 的 cache java -XX:AOTCacheOutput=app.aot -cp app.jar com.example.App ... # 生产:加载 cache java -XX:AOTCache=app.aot -cp app.jar com.example.App ...
JEP 给出的公开基准方向(两核 Linux/x64、偏微服务争用场景):仅有类/剖析的 AOT cache 约可将若干框架应用启动缩短约 50%–70%;加上 AOT code 后约 65%–80%。javac 反复编译基准则显示:带 AOT code 的曲线更早贴近稳态,预热面积明显缩小。具体数字依赖工作负载与硬件,宜自行复测。
对照 Graal Native Image(点到为止)
| 维度 | JEP 544(HotSpot + AOT cache) | Graal Native Image(典型用法) |
|---|---|---|
| 产物形态 | 仍是 JVM 进程;cache 提供预编译原生码 | 多为独立原生可执行文件 |
| 动态性 | 保留动态类加载、反射等平台语义;负载变可再 JIT | 常依赖封闭世界 / 配置与约束,动态特性需额外处理 |
| 峰值与漂移 | 设计目标含「可去优化再优化」 | 静态优化面向训练所见热点,运行时再塑空间更有限 |
| 移植 | 训练与生产同架构同特性;换 CPU 特性可能丢弃 AOT code | 需按目标平台重新构建镜像 |
| 工作流 | 扩展现有 Leyden AOT cache,应用代码零改(目标) | 构建期 AOT,常需 native 构建链路与可达性配置 |
两者都在「把编译前移」上用力,但 544 刻意保留 HotSpot 的敏捷与可移植叙事:要的是 AOT 的启动/预热红利 + JIT 的持续峰值,而不是用静态镜像替换 JVM。选型上,极致冷启动与镜像体积场景仍可能倾向 Native Image;希望少改代码、守住动态 Java、又想压启动的服务,则 Leyden 路线更贴近「渐进增强」。
对 Spring Boot 微服务冷启动的含义(点到即可)
对典型 Spring Boot 微服务而言,冷启动痛点往往来自类加载、元数据与早期热点编译争用 CPU。483/515 已从前端「装好类、备好剖析」;544 若最终进入 JDK 28,则意味着训练环境跑一轮代表性流量后,生产实例有机会少做一轮 C2 热身。这与「把 G1 / 对象头默认布局理顺」是同一条时间线上的不同层:上一篇关注默认布局与 GC,本稿关心的是编译工作前移。实操上仍要保证训练负载像生产、GC 与 CPU 特性一致,并接受 cache 体积可能明显变大——JEP 也提示可用 -XX:-AOTCodeCaching(需诊断解锁)评估体积与收益。再次强调:本稿撰写时 JEP 544 仅为 Proposed to Target,不可按已发布特性排期上线。
观察与排障入口(仍以文档为准)
生产侧可用既有 -XX:+PrintCompilation 观察 AOT code 加载与 JIT 编译是否交织出现;若要用「cache 不可用就失败」做环境门禁,JEP 提到 AOTMode=required(由早期的 AOTMode=on 更名)。当仅想评估「关掉 AOT code、仍用类与剖析」的收益差时,可配合诊断选项关闭 AOTCodeCaching。上述开关名称与默认值可能随 EA 变动,本文未本地验证,上线前请对照对应构建的 java 手册与 JEP 更新记录。
对持续交付而言,更稳妥的姿势是:把训练跑固定在与生产同架构、同 GC、同关键 CPU feature 的镜像或节点上,把生成的 .aot 当作构建产物做版本化,并在金丝雀阶段对比「无 cache / 仅类与剖析 / 含 AOT code」三类启动曲线,而不是一上来全量切换。
小结与阅读建议
- 状态:Proposed to Target JDK 28(InfoQ 称评审曾预期于 2026-09-28 结束;以 OpenJDK JEP 页实时状态为准)。
- 能力:训练跑写入优化原生码 → 生产加载;AOT+JIT 共存;扩展既有 AOT cache。
- 边界:同架构/同 CPU 特性、同 GC;非纯 AOT、非交叉编译;约束不满足则丢弃 AOT code 但仍可用其余 cache。
- 对照:相对 Native Image,更偏「仍在 JVM 内加速」,而非封闭世界静态映像。
建议直接精读 JEP 544 的 Goals / Non-Goals / Consistency / Future Work,并对照 InfoQ 2026-09-21 周汇总 看其在 JDK 28 候选池中的位置。等状态变为 Targeted 或随 EA build 可实测后,再谈流水线里固化训练产物与回归对比不迟。
一起交流
分享你的思考,让讨论更进一步。