bigywater.tech
Java · 394

Compiler Queue:哪些方法正在等待 JIT 编译

有哪些方法正在排队等待 JIT 编译?这篇用 jcmd 取样编译队列,量出队列长度、编译线程数与完成时间的关系、-Xbatch 的代价,并如实记录一个预期没有出现的现象。

9
3000 个方法的洪水下,C2 编译队列取样到的最大长度(C1 队列始终为空)
1861 → 1666 ms
CICompilerCount 从 2 增加到 8 时同一负载的总用时
1739 vs 898 ms
-Xbatch 与默认后台编译的 3 轮总用时

观察队列

实测 · 本机执行输出
  本机默认 CICompilerCount = 4(逻辑 CPU 10 个)
  [默认编译线程] 共取样 8 次;C1 队列非空 0 次,C2 队列非空 3 次;C2 队列长度最大 9,C1 队列长度最大 0,同时在编译的最多 3 个;程序自己报告 total 1750
      取样时刻 / 正在编译 / C1 队列 / C2 队列:0.3s 0/0/0;  0.5s 3/0/9;  0.7s 3/0/5;  0.9s 3/0/4;  1.1s 0/0/0;  1.2s 0/0/0;  1.4s 0/0/0;  1.6s 0/0/0
      C2 队列最长时的快照(节选):
          Current compiles: 
          C2 CompilerThread0  3151       4       Flood::m43 (43 bytes)
          C2 CompilerThread1  3150       4       Flood::m38 (43 bytes)
          C2 CompilerThread2  3152       4       Flood::m48 (43 bytes)
          C1 compile queue:
          Empty
          C2 compile queue:
          3153       4       Flood::m53 (42 bytes)
          3154       4       Flood::m58 (43 bytes)
  [-XX:CICompilerCount=2(1 个 C1 + 1 个 C2)] 共取样 9 次;C1 队列非空 0 次,C2 队列非空 5 次;C2 队列长度最大 7,C1 队列长度最大 0,同时在编译的最多 1 个;程序自己报告 total 1897
      取样时刻 / 正在编译 / C1 队列 / C2 队列:0.3s 0/0/0;  0.5s 1/0/2;  0.7s 1/0/5;  0.8s 1/0/4;  1.0s 1/0/7;  1.2s 1/0/6;  1.4s 0/0/0;  1.6s 0/0/0;  1.8s 0/0/0
      C2 队列最长时的快照(节选):
          Current compiles: 
          C2 CompilerThread0  4558       4       Flood::m337 (45 bytes)
          C1 compile queue:
          Empty
          C2 compile queue:
          4559       4       Flood::m342 (43 bytes)
          4560       4       Flood::m347 (45 bytes)
          4561       4       Flood::m352 (44 bytes)
          4562       4       Flood::m357 (44 bytes)

编译线程数

实测 · 本机执行输出
  CICompilerCount=2:总用时中位数 1861 ms(最快 1858,最慢 1865);第 0 轮 406 ms,第 1 轮 292 ms,第 7 轮 163 ms
  CICompilerCount=3:总用时中位数 1769 ms(最快 1760,最慢 1775);第 0 轮 405 ms,第 1 轮 295 ms,第 7 轮 164 ms
  默认(4):总用时中位数 1730 ms(最快 1723,最慢 1732);第 0 轮 407 ms,第 1 轮 283 ms,第 7 轮 167 ms
  CICompilerCount=8:总用时中位数 1666 ms(最快 1655,最慢 1676);第 0 轮 389 ms,第 1 轮 289 ms,第 7 轮 162 ms

-Xbatch

实测 · 本机执行输出
  默认(后台编译):3 轮总用时中位数 898 ms(最快 898,最慢 898);第 0 轮 409 ms,第 2 轮 205 ms
  -Xbatch:3 轮总用时中位数 1739 ms(最快 1739,最慢 1747);第 0 轮 693 ms,第 2 轮 165 ms
  -Xint(不编译):3 轮总用时中位数 2234 ms(最快 2230,最慢 2241);第 0 轮 741 ms,第 2 轮 741 ms

热点方法有没有变晚

实测 · 本机执行输出
  [只有 Probe] 稳态每批 0.053 ms;前 3 批 0.29 0.19 0.19 ms;连续 5 批都 <= 1.5 倍稳态 从第 39 批(时刻 4 ms)开始;最慢的一批 0.29 ms  ||  稳态每批 0.053 ms;前 3 批 0.31 0.19 0.19 ms;连续 5 批都 <= 1.5 倍稳态 从第 40 批(时刻 4 ms)开始;最慢的一批 0.31 ms  ||  稳态每批 0.053 ms;前 3 批 0.29 0.19 0.19 ms;连续 5 批都 <= 1.5 倍稳态 从第 40 批(时刻 4 ms)开始;最慢的一批 0.29 ms
  [Probe + 洪水(默认编译线程)] 稳态每批 0.055 ms;前 3 批 0.29 0.19 0.19 ms;连续 5 批都 <= 1.5 倍稳态 从第 41 批(时刻 4 ms)开始;最慢的一批 0.29 ms  ||  稳态每批 0.055 ms;前 3 批 0.29 0.19 0.20 ms;连续 5 批都 <= 1.5 倍稳态 从第 40 批(时刻 4 ms)开始;最慢的一批 0.29 ms  ||  稳态每批 0.055 ms;前 3 批 0.29 0.19 0.19 ms;连续 5 批都 <= 1.5 倍稳态 从第 41 批(时刻 4 ms)开始;最慢的一批 0.29 ms
  [Probe + 洪水,CICompilerCount=2] 稳态每批 0.056 ms;前 3 批 0.42 0.20 0.19 ms;连续 5 批都 <= 1.5 倍稳态 从第 4 批(时刻 1 ms)开始;最慢的一批 0.42 ms  ||  稳态每批 0.053 ms;前 3 批 0.36 0.20 0.18 ms;连续 5 批都 <= 1.5 倍稳态 从第 41 批(时刻 4 ms)开始;最慢的一批 0.36 ms  ||  稳态每批 0.055 ms;前 3 批 0.44 0.19 0.19 ms;连续 5 批都 <= 1.5 倍稳态 从第 40 批(时刻 4 ms)开始;最慢的一批 0.44 ms

分步演示

JIT 编译队列
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12;10 个逻辑 CPU,默认 CICompilerCount = 4;负载是生成的 3000 个小方法(Flood)与一个 40 次迭代循环的 probe 方法;取样间隔约 0.15 s,会错过更短的队列峰值
    • 没有验证:编译任务的选取顺序(热度 / 先后)、更大的方法与 JDK 25 / Graal 编译器下的队列、-XX:+PrintCompilation 日志的对照、代码缓存(CodeCache)满时的行为、JVMCI 编译线程
    京ICP备2026067502号-1京公网安备11010502063487号