0%

即时编译器

即时编译器(JIT):Java 性能优化的核心引擎

即时编译器(Just-In-Time Compiler,JIT)是 HotSpot 虚拟机提升代码执行效率的关键组件。它通过将 “热点代码”(频繁执行的代码)编译为本地机器码,弥补了解释器执行效率低的缺陷,使 Java 既能保持跨平台性,又能接近原生代码的运行速度。

解释器与编译器的协同:混合模式的优势

Java 采用 “解释器 + 即时编译器” 的混合架构(mixed mode),两种组件各有侧重,协同工作:

解释器的角色

解释器是 JVM 执行代码的基础组件,其工作方式是逐行翻译字节码为机器码并立即执行

  • 优点:启动速度快(无需提前编译),适合程序启动阶段或低频执行的代码(如初始化代码)。
  • 缺点:执行效率低(每条指令需重复翻译),不适合高频执行的代码(如循环、核心业务方法)。

即时编译器的角色

JIT 编译器的核心目标是将热点代码编译为优化后的本地机器码并缓存,避免重复解释。

  • 优点:执行效率高(机器码直接运行,无需重复翻译),适合高频执行的热点代码。
  • 缺点:编译过程本身耗时(需分析代码、优化、生成机器码),不适合启动阶段(可能拖慢启动速度)。

混合模式的价值

混合模式结合了两者的优势:

  • 启动阶段:解释器优先工作,确保程序快速启动(无需等待 JIT 编译)。
  • 运行阶段:JIT 编译器逐步将热点代码编译为机器码,提升长期执行效率。

通过 java -version 可查看当前模式,默认显示 mixed mode

1
2
java -version
# 输出:Java HotSpot(TM) 64-Bit Server VM (build 25.261-b12, mixed mode)

热点探测:如何识别 “热点代码”?

JIT 编译器仅针对 “热点代码”(频繁执行的代码)进行编译,避免无意义的资源消耗。判断代码是否为热点的过程称为 “热点探测”,HotSpot 采用基于计数器的热点探测(更精准),而非基于采样的方式。

两种核心计数器

HotSpot 为每个方法维护两个计数器,共同判断代码热度:

  • 方法调用计数器:统计方法被调用的总次数。
  • 回边计数器:统计方法中循环的执行次数(“回边” 指循环跳转的边缘,如 for 循环的迭代)。

阈值与触发编译

当计数器累计值超过阈值时,JIT 会触发编译:

  • 方法调用计数器阈值:Client 模式下为 1500 次,Server 模式下为 10000 次(可通过 -XX:CompileThreshold 调整)。
  • 回边计数器阈值:由方法调用阈值和 OSR(On-Stack Replacement,栈上替换)比率计算得出,公式为:
    回边阈值 = 方法调用阈值 × OSR比率 ÷ 100
    (OSR 比率默认:Client 模式 933,Server 模式 140,可通过 -XX:OnStackReplacePercentage 调整)。

热度衰减:避免 “冷代码” 被编译

为防止不常执行的代码因偶然高频调用被编译,JIT 引入 “热度衰减” 机制:

  • 若方法在一段时间(半衰周期)内调用次数未达阈值,调用计数器会减半(“热度衰减”)。
  • 半衰周期默认 30 秒(可通过 -XX:CounterHalfLifeTime 调整)。

参数配置:

  • -XX:-UseCounterDecay:关闭热度衰减(默认开启),此时计数器不会减半,长期运行后多数方法会被编译。

编译触发流程

当方法被调用时,JIT 会按以下流程判断是否编译:

  1. 检查该方法是否已有编译后的本地代码,若有则直接执行;
  2. 若无,则将方法调用计数器 +1,回边计数器按循环执行次数累加;
  3. 若两者之和超过阈值,向 JIT 提交编译请求,后台编译为本地代码;
  4. 编译期间,仍由解释器执行,编译完成后切换为本地代码。

热点探测方式对比

探测方式 原理 优点 缺点 代表虚拟机
基于采样 周期性检查线程栈顶,统计高频方法 实现简单,易获取调用关系 精度低,易受线程阻塞干扰 J9 虚拟机
基于计数器 为方法 / 循环维护计数器,统计执行次数 精度高,结果严谨 实现复杂,需维护计数器 HotSpot 虚拟机

JIT 编译的核心参数配置

参数 作用 默认值(Server 模式)
-XX:CompileThreshold 方法调用计数器阈值 10000 次
-XX:OnStackReplacePercentage OSR 比率(计算回边阈值) 140
-XX:+UseCounterDecay 开启热度衰减(关闭为 -XX:-UseCounterDecay 开启(+
-XX:CounterHalfLifeTime 热度衰减的半衰周期(秒) 30 秒
-Xint 强制使用解释模式(禁用 JIT) 不启用(默认混合模式)
-Xcomp 强制使用编译模式(优先 JIT) 不启用(默认混合模式)

欢迎关注我的其它发布渠道