1. ホーム
  2. java

[解決済み] Java JITは、JDKのコードを実行するときに不正をするのですか?

2022-03-22 07:18:56

質問

あるコードをベンチマークしていたのですが、そのコードが java.math.BigInteger 全く同じアルゴリズムを使っていてもです。 そこで私は java.math.BigInteger のソースを自分のパッケージに入れ、これを試してみました。

//import java.math.BigInteger;

public class MultiplyTest {
    public static void main(String[] args) {
        Random r = new Random(1);
        long tm = 0, count = 0,result=0;
        for (int i = 0; i < 400000; i++) {
            int s1 = 400, s2 = 400;
            BigInteger a = new BigInteger(s1 * 8, r), b = new BigInteger(s2 * 8, r);
            long tm1 = System.nanoTime();
            BigInteger c = a.multiply(b);
            if (i > 100000) {
                tm += System.nanoTime() - tm1;
                count++;
            }
            result+=c.bitLength();
        }
        System.out.println((tm / count) + "nsec/mul");
        System.out.println(result); 
    }
}

これを実行すると(MacOSのjdk 1.8.0_144-b01)、出力されます。

12089nsec/mul
2559044166

import行をアンコメントして実行すると。

4098nsec/mul
2559044166

JDK版のBigIntegerを使った場合と私のバージョンを使った場合では、まったく同じコードを使っていても、ほぼ3倍の速度が出ます。

javapでバイトコードを調べたり、オプションを付けて実行したときのコンパイラの出力を比較したりしました。

-Xbatch -XX:-TieredCompilation -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions 
-XX:+PrintInlining -XX:CICompilerCount=1

で、どちらのバージョンも同じコードを生成しているようです。 ということは、hotspotは、私のコードでは使えないような、事前に計算された最適化を使っているのでしょうか?私は、そうではないと理解しています。 この違いは何なのでしょうか?

解決方法は?

そう、HotSpot JVMは、ある種の不正行為です。 BigInteger メソッドは、Javaのコードにはないものです。これらのメソッドは JVM intrinsics .

具体的には BigInteger.multiplyToLen はHotSpotの固有メソッドです。また、特殊な ハンドコードされたアセンブリ実装 は、JVMのソースベースに含まれていますが、x86-64アーキテクチャのみです。

この組み込みを無効にするには -XX:-UseMultiplyToLenIntrinsic オプションを使用すると、JVMは純粋なJavaの実装を使用するように強制されます。この場合、パフォーマンスはコピーしたコードのパフォーマンスと同様になります。

追伸 以下は リスト その他のHotSpotの固有メソッドを紹介します。