JEP 544 想解决 Java 的启动和预热,AOT 编译该怎么落地

JEP 544 在 Hacker News 获得 94 points 和 39 条评论。它提出通过训练运行生成提前编译代码,把优化结果保存进 AOT 缓存,让生产进程减少解释、类加载和即时编译带来的启动与预热等待。这个方向特别适合短生命周期服务、弹性扩容和对首个请求敏感的应用。

AOT 和 JIT 的关系

JIT 会根据真实运行时信息优化代码,适应性强,却需要时间收集 profile。AOT 把一部分工作放到运行前,启动更快,代价是训练数据可能不完整,生成的代码未必适合所有线上负载。JEP 544 的价值在于保存训练结果,让生产启动直接利用此前得到的优化信息。

它不是把 Java 变成完全静态的本地程序。应用仍依赖 JVM 的运行能力,动态行为和实际负载仍可能触发后续 JIT。

哪些系统值得试

函数计算、批处理 worker、频繁发布的容器和自动扩缩容服务,通常更在意启动时间。长时间运行、负载稳定的服务可能已经充分完成预热,AOT 的收益就要用真实指标确认。

评估流程

  1. 分开测冷启动、首次请求、达到稳定吞吐的时间。
  2. 采集生产相似流量下的 profile,不能只用一个 hello world。
  3. 比较 AOT 缓存体积、构建耗时、内存占用和峰值吞吐。
  4. 在不同 CPU、JDK 和容器镜像上做兼容性测试。
  5. 预留缓存失效和回退到普通 JIT 的路径。

容易误判的地方

启动时间变短不代表总成本下降。训练运行、缓存生成、镜像分发和版本失配都可能增加发布成本。若 profile 与真实请求差异很大,应用可能在生产中继续编译,收益会打折。

部署时要把 AOT 缓存当成版本化产物。JDK、应用类、启动参数、CPU 特性和依赖变化,都可能让旧缓存失效。容器镜像里应明确缓存由哪一步生成,启动时如何检查版本,不匹配时怎样回退。性能测试还要包含滚动发布,因为新旧实例并存会改变流量分布和预热观察结果。

对开发团队来说,最实用的起点是选择一个启动慢且请求路径稳定的服务做对照实验。先拿到冷启动和首个请求的基线,再决定是否值得承担训练和发布复杂度。

还要区分首个请求和稳定请求。AOT 缓存可能让服务更快接受第一批流量,却未必提高长期吞吐。压测应覆盖不同并发、缓存命中和实例重启,观察收益是否集中在扩容窗口,避免用单次启动时间替代完整判断。

FAQ

AOT 会取代 JIT 吗?不会。两者解决不同阶段的问题,混合使用更符合 JVM 的运行方式。

只跑一次训练就够吗?通常不够。训练样本应覆盖关键路径和版本变化。

如何证明收益?同时记录冷启动、预热、吞吐、内存和构建成本,不能只看单一延迟数字。