Java执行效率提升核心在于JIT编译器动态将热路径字节码编译为机器码,通过计数器识别热点、分层编译(C1快速基础优化/C2深度优化)、去优化保障正确性、内联缓存与代码缓存降低开销。

Java 的执行效率提升,核心在于 JIT(Just-In-Time)编译器将频繁执行的字节码“热路径”动态编译为本地机器码,绕过解释执行的开销。它不是一次性全量编译,而是基于运行时行为做智能决策,兼顾启动速度与长期性能。
热点代码识别:靠计数器驱动的运行时观测
JIT 不会编译所有代码,只聚焦真正“热”的部分。JVM 通过两类计数器持续监控:
- 方法调用计数器:记录方法被调用次数,达到阈值(如 Server 模式默认 10000 次)触发 C1 或 C2 编译
- 回边计数器:专用于循环体,统计循环回跳(loop back-edge)次数,识别高频执行的循环内部逻辑
计数器并非简单累加——执行过程中会周期性衰减(counter decay),避免长期闲置的方法残留高计数;同时支持分层编译(Tiered Compilation),先用轻量级 C1 快速生成带少量优化的本地码,再由 C2 对持续热门的方法做深度优化。
分层编译策略:C1 与 C2 协同工作的两级优化体系
现代 HotSpot JVM 默认启用分层编译(-XX:+TieredStopAtLevel=1 可禁用),形成流水线式优化:
立即学习“Java免费学习笔记(深入)”;
- C1(Client Compiler):编译快、开销低,做基础优化(如方法内联、空值检查消除、简单逃逸分析),适合响应敏感场景
- C2(Server Compiler):编译慢但优化激进,支持循环展开、向量化、虚函数去虚拟化(devirtualization)、冗余内存访问消除等,需更多 profiling 数据支撑
方法初热时由 C1 编译并插桩收集执行路径、分支频率、对象分配模式等信息;若持续热点,JVM 将其升级至 C2 队列,用更完整的运行时数据生成更高性能的机器码,并替换原有版本(即 Code Cache 中的旧版本)。
去优化(Deoptimization):保证正确性的动态回退机制
JIT 编译依赖运行时假设(如某虚方法实际只有一种实现、某对象始终未逃逸)。一旦这些假设被打破(如新类加载导致多态分支增加、对象逃逸到方法外),已编译的代码就可能不安全。
此时 JVM 触发去优化:
- 暂停对应线程,将当前执行栈“炸开”,还原为解释执行状态
- 把现场变量和表达式状态映射回字节码栈帧,继续以解释器方式运行
- 后续若再次变热,会基于新 profile 数据重新编译(可能生成更保守或更适配的新版本)
去优化是 JIT 可靠性的关键设计,它让激进优化不再成为正确性的威胁,而是可逆的性能赌注。
代码缓存与内联缓存:减少间接跳转与动态分派开销
除了主流程编译,JIT 还在底层嵌入两项关键优化:
- 内联缓存(Inline Caching):对 invokevirtual / invokeinterface 指令,首次执行时记录实际目标方法地址;后续调用直接比对接收者类型,命中则跳转执行,避免查虚方法表(vtable / itable)
- 代码缓存(Code Cache)管理:已编译的本地码存储在独立内存区,JIT 动态管理其大小、淘汰冷代码、防止碎片化;可通过 -XX:ReservedCodeCacheSize 调整容量
这些细粒度优化叠加在方法级编译之上,进一步压缩了动态语言特性带来的运行时成本。
JIT 的本质,是用运行时可观测性换编译时确定性,用可控的去优化换激进的优化空间。它让 Java 在保持跨平台与安全性的同时,接近原生代码的执行效率。










