部分的な回答であり、将来の調査が必要です。しかし、当面は答えはです。これはJIT最適化の効果です。また、特にJavaのような動的にコンパイルされた言語では、マイクロベンチマークがパフォーマンステストの最良の選択肢ではないことに注意してください(例:this guru paper参照)。
私は、Windows 10のホーム、java -version
版画使用しています:
Javaバージョン "1.8.0_121"
のJava(TM)SEランタイム環境(ビルド1.8.0_121-B13)
は、Java HotSpot(TMを)64ビットサーバーVM(私は離れて最適化されていません、次のようにコードを再構築し、ループを確保するために、外部カウンタとしてx
を追加した
)、混合モードを25.121-B13を構築:
void test1() {
int x = 0;
long b = System.currentTimeMillis();
for (int i = 0; i < 100_001; i++) {
int t = 0;
while (i != t++) {
x++;
}
}
long b1 = System.currentTimeMillis();
System.out.println("T(test1) = " + (b1 - b));
System.out.println("x(test1) = " + x);
}
void test2() {
int x=0;
long b = System.currentTimeMillis();
for (int i = 0; i < 100001; i++) {
int t = 0;
while (t++ != i) {
x++;
}
}
long b1 = System.currentTimeMillis();
System.out.println("T(test2) = " + (b1 - b));
System.out.println("x(test2) = " + x);
}
各関数が2回呼び出され:
T(TEST1)= 3745:
t.test1();
t.test1();
t.test2();
t.test2();
[OK]を、のは、標準java Test
呼び出しの結果を(他のinterpeterの引数が指定されていない)を見てみましょう
x705082704
T(test1)= 0
x(test1)= 705082704
T(TEST2)では、第二の呼び出した後、実行時間を見ることができるように5
X(TEST2)= 705082704
T(TEST2)= 0
X(TEST2)= 705082704
を=どちらの場合も0に等しい。たとえ2番目の呼び出し結果がキャッシュされていないことを保証するためにint x = 0
の初期化をint x = new Random().nextInt()
に変更しても同じことが起こります。一般に、測定を行う前にJavaインタープリタを「ウォーミングアップ」する必要があります。つまり、同じ実行でコードのパフォーマンスを2回測定し、最初の結果をスローアウェイして、最適化が確実に行われるようにします。しかし、それはオンラインジャッジの演習を解決する際には持っていない贅沢です。
他の部分はここになります。 OracleのJDKには-Xint
インタプリタ・スイッチがあり、JITを完全にオフにします。それを使って何が起こるか見てみましょう。私は-XX:+PrintCompilation
フラグを使ってコンパイルが行われていないことを確認しました。インタプリタはjava -XX:+PrintCompilation -Xint Test
として呼び出されました。追加の診断)コードがコンパイルされなかったことを意味印刷されていない場合:
T(TEST1)= 56610
X(TEST1)= 705082704
T(TEST1)= 55635
X(TEST1)= 705082704
T(TEST2)= 60247
X(TEST2)= 705082704
T(TEST2)= 58249
X(TEST2)= 705082704
2つの観察:タスクには時間がかかり、結果はすべての呼び出しで似ています。 2つのコードがJITによって異なるように最適化されている理由を調べるためには、より多くの調査が必要です。
EDIT:JIT部分と楽しい2
だから、私は別のコンパイルオプションを試しに行ってきました。一般に、JITが使用するコンパイラには2種類あります。 C1(クライアント)コンパイラは、JVMの起動時間を短縮することを目的としていますが、C2(サーバー)コンパイラほど高速ではありません。私が使用している64ビットJava 8 JVMは、サーバを唯一の使いやすいオプションにしているようです(this FAQを参照してください。ただし、異なるコンパイルレベルは-XX:TieredStopAtLevel=
フラグで選択することができます。彼らは、サーバコンパイラのバージョンであることを支持して、test2
の最初の呼び出しをより速くする)。
私のマシンには32ビットのJREもあります。これは、サーバーのコンパイラをサポートし、次のバージョン情報与えていません:
Javaバージョン "1.8.0_121"
のJava(TM)SEランタイム環境(ビルドを1.8.0_121-B13)
は、Java HotSpot(TM)クライアントVM(25.121-B13、混在モードの構築)以下のように、このJVMの
結果は次のとおり
T(TEST1)= 3947
X(TEST1)を= 705082704
T(TEST1)= 3985
X(TEST1)= 705082704
T(TEST2)= 4031
X(TEST2)= 705082704
T(TEST2)= 4172
X(TEST2)= 705082704
TLEとは何ですか? –
時間制限超過 –
これを読んでくださいhttp://stackoverflow.com/a/5413593/5617860 – Omore