final
それが主な目的ではないとしても、キーワード (場合によっては VM の実装で) が JIT に役立つ可能性があると私は常に考えてきました。
都市伝説かもしれませんが、フィールドを設定するfinal
ことでパフォーマンスに悪影響を及ぼすとは思いもしませんでした。
そのようなコードに遭遇するまで:
private static final int THRESHOLD = 10_000_000;
private static int [] myArray = new int [THRESHOLD];
public static void main(String... args) {
final long begin = System.currentTimeMillis();
//Playing with myArray
int index1,index2;
for(index1 = THRESHOLD - 1; index1 > 1; index1--)
myArray[index1] = 42; //Array initial data
for(index1 = THRESHOLD - 1; index1 > 1; index1--) {
//Filling the array
for(index2 = index1 << 1; index2 < THRESHOLD; index2 += index1)
myArray[index2] += 32;
}
long result = 0;
for(index1 = THRESHOLD - 1; index1 > 1; index1-=100)
result += myArray[index1];
//Stop playing, let's see how long it took
System.out.println(result);
System.out.println((System.currentTimeMillis())-begin+"ms");
}
見てみましょう:
private static int [] myArray = new int [THRESHOLD];
W7 64 ビットで、10 回の連続実行に基づいて、次の結果が得られます。
THRESHOLD = 10^7
、1.7.0u09 クライアント VM (Oracle):myArray
が最終ではない場合、約 2133 ミリ秒で実行されます。myArray
が最終的な場合、〜 2287 ミリ秒で実行されます。- -server VM では、2131 ミリ秒と 2284 ミリ秒という同様の数値が生成されます。
THRESHOLD = 3x10^7
、1.7.0u09 クライアント VM (Oracle):myArray
最終ではない場合、〜 7647 ミリ秒で実行されます。myArray
が最終的な場合、〜 8190 ミリ秒で実行されます。- -server VM は ~7653ms と ~8150ms を生成します。
THRESHOLD = 3x10^7
、1.7.0u01 クライアント VM (Oracle):myArray
最終ではない場合、約 8166 ミリ秒で実行されます。myArray
が最終的なときは ~9694ms で実行されます。その差は15%以上!- -server VM は、非最終バージョンを支持する無視できる差異 (約 1%) を生成します。
注意: すべてのテストで、JDK 1.7.0u09 の javac によって生成されたバイトコードを使用しました。myArray
生成されたバイトコードは、宣言を除いて、両方のバージョンでまったく同じです。
では、なぜ のバージョンは のバージョンstatic final myArray
よりも遅いのstatic myArray
でしょうか?
編集(私のスニペットのAubinのバージョンを使用):
final
キーワードを含むバージョンと含まないバージョンの違いは、最初の反復のみにあるようです。どういうわけか、final
最初の反復では、 を使用したバージョンは常に対応するバージョンよりも遅くなり、次の反復では同様のタイミングになります。
たとえば、THRESHOLD = 10^8
1.7.0u09 クライアントで実行すると、最初の計算には約 35 秒かかりますが、2 番目の「のみ」には 30 秒かかります。
明らかに、VM は最適化を実行しました。それは JIT が動作していたのですが、なぜ以前に起動しなかったのですか (たとえば、ネストされたループの 2 番目のレベルをコンパイルすることによって、この部分がホットスポットでした)。
私の発言は 1.7.0u01 クライアント VM でも有効であることに注意してください。そのバージョン(およびおそらく以前のリリース) では、このキーワードを使用しないコードfinal myArray
よりも実行速度が遅くなります: 200 回の反復に基づいて 2671ms 対 2331ms です。