分层编译(Tiered Compilation)
理解分层编译,是理解 JVM 如何在不同阶段选择不同优化策略的基础。
为什么需要分层编译
传统的 JVM 面临一个权衡:
分层编译解决了这个矛盾:
分层编译的四个层次
各层详解
Tier 0:解释执行
- 字节码直接被解释执行
- 统计方法调用次数和回边次数
- 不生成任何编译代码
Tier 1:C1 快速编译
- 方法调用次数超过阈值后触发
- 使用 C1 编译器快速生成代码
- 不进行深度优化
Tier 2:C1 + Profiling
- C1 编译后继续统计 profiling 数据
- 采集类型信息、分支信息等
- 为 C2 编译提供数据
Tier 3:C2 深度优化
- 基于 profiling 数据进行激进优化
- 生成高质量机器码
- 可能进行去优化
分层编译的配置
启用分层编译
分层编译在 JDK 8+ 默认启用:
编译阈值参数
编译线程数
分层编译的工作流程
正常编译路径
去优化路径
分层编译的优势
1. 快速启动
2. 更快的预热
分层编译让应用更快达到峰值性能:
3. 适应不同负载
分层编译能适应不同的热点分布:
- 启动期:主要是 Tier 0 和 Tier 1
- 预热期:Tier 2 采集数据
- 稳定期:Tier 3 达到峰值性能
分层编译的监控
JIT 日志
PrintCompilation
日志符号说明
分层编译的注意事项
1. 代码缓存
分层编译会生成多层代码,需要更大的代码缓存:
2. 编译线程
编译线程数影响编译速度:
3. 内存开销
分层编译需要额外的 profiling 数据:
适用场景
分层编译适合几乎所有场景,特别是:
- 服务应用:需要快速启动并达到峰值性能
- 微服务:启动时间直接影响资源利用
- 容器化部署:启动快意味着更快的弹性伸缩
- 长时间运行:预热后达到最优性能