首先,问题与模块系统无关(直接)。
我注意到,即使使用JDK 9,其第一个预热迭代
newInstance也与使用JDK 8一样快。
# Fork: 1 of 1# Warmup Iteration 1: 10,578 ns/op <-- Fast!# Warmup Iteration 2: 246,426 ns/op# Warmup Iteration 3: 242,347 ns/op
这意味着JIT编译中出现了问题。
-XX:+PrintCompilation确认基准是在第一次迭代后重新编译的:
10,762 ns/op# Warmup Iteration 2: 1541 689 ! 3 java.lang.Class::newInstance (160 bytes) made not entrant 1548 692 % 4 bench.generated.NewInstance_newInstance_jmhTest::newInstance_avgt_jmhStub @ 13 (56 bytes) 1552 693 4 bench.generated.NewInstance_newInstance_jmhTest::newInstance_avgt_jmhStub (56 bytes) 1555 662 3 bench.generated.NewInstance_newInstance_jmhTest::newInstance_avgt_jmhStub (56 bytes) made not entrant248,023 ns/op
然后
-XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining指出内联问题:
1577 667 % 4 bench.generated.NewInstance_newInstance_jmhTest::newInstance_avgt_jmhStub @ 13 (56 bytes) @ 17 bench.NewInstance::newInstance (6 bytes) inline (hot) ! @ 2 java.lang.Class::newInstance (160 bytes) already compiled into a big method
消息“已经编译为大方法”
表示编译器无法内联
Class.newInstance调用,因为被调用方的已编译大小大于
InlineSmallCode值(默认为2000)。
当我使用来重新运行基准测试时
-XX:InlineSmallCode=2500,它又变得很快了。
Benchmark Mode Cnt Score Error UnitsNewInstance.newInstance avgt 5 8,847 ± 0,080 ns/opNewInstance.operatorNew avgt 5 5,042 ± 0,177 ns/op
您知道,JDK 9现在将 G1作为默认GC 。如果我退回到Parallel
GC,即使使用default,基准测试也会很快
InlineSmallCode。
使用以下命令重新运行JDK 9基准测试
-XX:+UseParallelGC:
Benchmark Mode Cnt Score Error UnitsNewInstance.newInstance avgt 5 8,728 ± 0,143 ns/opNewInstance.operatorNew avgt 5 4,822 ± 0,096 ns/op
G1要求每当对象存储发生时就设置一些障碍,这就是为什么编译后的代码会变得更大一些,从而
Class.newInstance超过默认
InlineSmallCode限制。编译
Class.newInstance变得更大的另一个原因是,反射代码已在JDK
9中进行了稍微的重写。
TL; DR
JIT无法内联Class.newInstance,因为InlineSmallCode已超出限制。Class.newInstance由于JDK
9中反射代码的更改以及默认GC已更改为G1,因此的编译版本变得更大。



