一个方法只被调用一次,里面的循环却要跑很久,JIT 怎么才能在循环中途换成编译后的代码?这篇用循环耗时曲线、关闭 OSR 的对照和 PrintCompilation 的 % 记录,把这件事演示出来。
[默认(OSR 开,分层编译)]
每 2 百万次迭代的 ns/迭代(桶号:值):1:2.0 2:1.2 3:0.7 4:0.7 5:0.7 6:0.7 7:0.7 8:0.7 9:0.7 10:0.7 11:0.7 12:0.7 13:0.7 14:0.7
[-XX:-UseOnStackReplacement(关闭 OSR)]
每 2 百万次迭代的 ns/迭代(桶号:值):1:26.0 2:26.0 3:26.0 4:26.0 5:26.1 6:26.2 7:26.1 8:26.0 9:26.2 10:26.1 11:26.0 12:26.2 13:26.0 14:26.1
[-Xint(只解释执行)]
每 2 百万次迭代的 ns/迭代(桶号:值):1:23.8 2:23.4 3:23.5 4:23.5 5:23.5 6:23.9 7:23.7 8:23.6 9:23.5 10:24.2 11:23.9 12:23.4 13:23.6 14:23.4
[-XX:TieredStopAtLevel=1(只用 C1)]
每 2 百万次迭代的 ns/迭代(桶号:值):1:2.2 2:1.3 3:1.3 4:1.3 5:1.4 6:1.4 7:1.4 8:1.4 9:1.4 10:1.4 11:1.4 12:1.4 13:1.4 14:1.4
[-XX:-TieredCompilation(只用 C2)]
每 2 百万次迭代的 ns/迭代(桶号:值):1:1.3 2:1.3 3:0.7 4:0.7 5:0.7 6:0.7 7:0.7 8:0.7 9:0.7 10:0.7 11:0.7 12:0.7 13:0.7 14:0.7 17 5 % 3 Main::main @ 34 (206 bytes)
17 6 3 Main::main (206 bytes)
18 7 % 4 Main::main @ 34 (206 bytes)
18 5 % 3 Main::main @ 34 (206 bytes) made not entrant
19 7 % 4 Main::main @ 34 (206 bytes) made not entrant
19 8 % 3 Main::main @ 34 (206 bytes)
20 9 % 4 Main::main @ 34 (206 bytes)
21 8 % 3 Main::main @ 34 (206 bytes) made not entrant
38 9 % 4 Main::main @ 34 (206 bytes) made not entrant (时间戳 ms,tier,@bci): [('17', '3', '34'), ('18', '4', '34'), ('18', '3', '34'), ('19', '4', '34'), ('19', '3', '34'), ('20', '4', '34'), ('21', '3', '34'), ('38', '4', '34')]
同一次运行里各桶的耗时: 每 2 百万次迭代的 ns/迭代(桶号:值):1:2.1 2:1.2 3:0.7 4:0.7 5:0.7 6:0.7 7:0.7 8:0.7 9:0.7 10:0.7 11:0.7 12:0.7 13:0.7 14:0.7 17 5 % 3 Nest::main @ 13 (60 bytes)
17 6 3 Nest::main (60 bytes)
17 7 % 4 Nest::main @ 13 (60 bytes)
18 5 % 3 Nest::main @ 13 (60 bytes) made not entrant
19 7 % 4 Nest::main @ 13 (60 bytes) made not entrant
20 8 % 3 Nest::main @ 13 (60 bytes)
20 9 % 4 Nest::main @ 13 (60 bytes)
21 8 % 3 Nest::main @ 13 (60 bytes) made not entrant
198 9 % 4 Nest::main @ 13 (60 bytes) made not entrant
字节码里的循环:外层循环头在偏移 4(36→39: goto 4),内层循环头在偏移 13(30→33: goto 13);PrintCompilation 里的 @ 后面是 OSR 入口的字节码偏移