21

2 番目のコードの方が速いのはなぜですか?

Map<Integer, Double> map = new HashMap<Integer, Double>();
for (int i = 0; i < 50000; i++) {
    for (double j = 0.0; j < 10000; j++) {
        map.put(i, j);
    }
}

Map<Integer, Double> map=new HashMap<Integer, Double>();
for (int i = 0; i < 50000; i++) {
    for (double j = 0.0; j < 10000; j++) {            
        map.put(new Integer(i), new Double(j));
    }
}
4

3 に答える 3

49

オートボクシングは を使用します。これはInteger.valueOf、小さい整数の Integer オブジェクトを内部的にキャッシュします (デフォルトでは -128 から 127 ですが、最大値は「java.lang.Integer.IntegerCache.high」プロパティで構成できます - Integer.valueOf のソース コードを参照してください)。ですので、new Integer直接呼び出すのとは異なります。Integer.valueOfは を呼び出す前に整数値の大きさをすばやくチェックするため、直接new Integer呼び出す方が少し高速new Integerです (小さな整数がたくさんある場合は、より多くのメモリを使用します)。Java での割り当ては非常に高速であり、GC を実行する時間はライブの短命オブジェクトの数に比例する (つまり、ガベージの量には比例しない) ため、GC も非常に高速です。

ただし、JVM のバージョンと有効になっている最適化によっては、スカラー置換の最適化があり、有効期間の短いオブジェクトを割り当てるときに、はるかに大きなパフォーマンスの違いが生じる可能性があります (この例では、保存しているため、最適化を行うことができません)。マップ内のオブジェクトですが、他の多くの状況で役立ちます)。

最近の JVM バージョンでは、スカラー置換の最適化があります (エスケープ解析が一時的に無効になっている 1.6.0_18 を除く)。つまり、存続期間の短いオブジェクトの割り当てを最適化して取り除くことができます。JVM のスカラー置換が新しくなったとき、誰かがあなたのコードに似たベンチマークを作成しました。その結果、プリミティブを使用したコードが最も速く、明示的なnew Integer()呼び出しを含むコードはプリミティブを使用したコードとほぼ同じ速さで、オートボクシングを使用したコードははるかに遅くなりました。これは、オートボクシングの使用Integer.valueOfと、少なくとも当時のスカラー置換の最適化では、その特別なケースが考慮されていなかったためです。それ以来、最適化が改善されたかどうかはわかりません。

于 2010-02-22T00:04:30.833 に答える
14

オートボクシングは and を使用Integer.valueOfDouble.valueOfます。これらのメソッドの呼び出しにはオーバーヘッドがあります (ただし、最終的にはインライン化されます)。またInteger.valueOf、プールされたインスタンスを使用するために低い値をチェックしますが、これはコードで成功することはあまりありません (ただし、ヒープ サイズを少し減らすことはできます)。プールされたインスタンスは、ヒープ サイズと GC 時間を削減し、同等性テストのパフォーマンスを向上させる可能性さえあるという利点があります。

しかし、一般的には、これは無視すべきマイクロ最適化です。

于 2010-02-21T23:31:24.103 に答える
7

マイクロベンチマークの結果が信頼できないからですか?

また、自動ボクシングは、コンストラクターではなく、Integer.valueOf() と Double.valueOf() を使用して行われます。

于 2010-02-21T23:30:26.533 に答える