Java JIT在运行JDK代码时会作弊吗?

我正在对一些代码进行基准测试,但我无法让它像java.math.biginger,即使使用完全相同的算法。
所以我复制了java.math.biginger将源代码放入我自己的包中,并尝试了以下操作:

//导入java.math.biginger;
公共类倍增测试{
公共静态void main(字符串[]args){
随机r=新随机(1);
长tm=0,计数=0,结果=0;
对于(int i=0;i<400000;i++){
int s1=400,s2=400;
BigInteger a=新的BigInteger(s1*8,r),b=新的BigInteger(s2*8,r);
long tm1=System.nanoTime();
大整数c=a乘以(b);
如果(i>100000){
tm+=System.nanoTime()-tm1;
计数++;
}
结果+=c.位长度();
}
System.out.println((tm/count)+“nsec/mul”);
系统输出打印项次(结果);
}
}

当我运行这个(MacOS上的jdk 1.8.0_144-b01)时,它输出:

12089nsec/mul
2559044166

在未注释导入行的情况下运行时:

4098nsec/mul
2559044166

使用JDK版本的BigInteger时,速度几乎是我的三倍,即使它使用的是完全相同的代码

我已经用javap检查了字节码,并比较了使用选项运行时的编译器输出:

-Xbatch-XX:-tieredcomilation-XX:+printcomilation-XX:+UnlockDiagnosticVMOptions
-XX:+printinline-XX:CICompilerCount=1

两个版本似乎生成相同的代码。
hotspot是否使用了一些我无法在代码中使用的预计算优化?我一直都明白他们不会。
是什么解释了这种差异

是的,HotSpot JVM有点“欺骗”,因为它有一些在Java代码中找不到的biginger方法的特殊版本。这些方法称为JVM内部函数

特别是,biginger.multiplyToLen是HotSpot中一种固有的方法。有一个特殊的在JVM源代码库中手工编码的程序集实现,但仅适用于x86-64体系结构

您可以使用-XX:-UseMultiplyToLentinTrinsic选项禁用此本质,以强制JVM使用纯Java实现。在这种情况下,性能将与复制的代码的性能相似

p.S.这里有一个列出其他热点内在方法

发表评论