2016-08-16 14 views
1

Javaでは、プリミティブ配列の場合、繰り返し再作成するよりもはるかに高速に配列を再利用していますか?Javaでは、プリミティブ配列の場合、繰り返し再作成するよりもはるかに高速に配列を再利用していますか?

次のスニペットは、2つのケースの比較です。(a)System.arrayCopyと(b)による配列の再利用は、集中的なループで指定された値の配列を繰り返し作成します。

public static void testArrayAllocationVsCopyPerformance() { 
    long time = System.currentTimeMillis(); 
    final int length = 3000; 

    boolean[] array = new boolean[length]; 

    boolean[] backup = new boolean[length]; 
    //for (int j = 0; j < length; j++) { 
    // backup [j] = true; 
    //} 

    for (int i = 0; i < 10000000; i++) { 
     //(a). array copy 
     //System.arraycopy(backup, 0, array, 0, length); 

     //(b). reconstruct arrays 
     array = new boolean[length]; 
     //for (int j = 0; j < length; j++) { 
     // array[j] = true; 
     //} 
    } 

    long millis = System.currentTimeMillis() - time; 
    System.out.println("Time taken: " + millis + " milliseconds."); 

    System.exit(0); 
} 

私のPCでは、(b)は平均で約2600ミリ秒かかりますが、(a)は平均で約450ミリ秒かかります。異なる値を持つ配列を再作成する場合、パフォーマンスギャップはさらに広がります。(b)平均で約3750ミリ秒、(a)は一定のままで、平均で450ミリ秒です。

上記のスニペットでは、 'boolean'が 'int'に変更された場合、結果は似ています。つまり、int配列の再利用には配列の再作成の1/3が必要です。加えて、(b)も(a)よりも読みにくくない。 (b)は、 'バックアップ'配列を必要としない(a)よりもわずかに読みにくいです。

しかし、Javaオブジェクトの作成に関するstackoverflowまたはstackexchangeに関する同様の質問の回答は、「ボトルネックになるまで最適化しないでください」、「今日のJITまたはJVMで処理することができます。 「読みやすくするためにシンプルにする」などです。そして、これらの種類の回答は、一般的に視聴者によく受け取ります。

質問:上記のパフォーマンス比較スニペットでは、短命のプリミティブ配列を使用した配列の再作成と比較して、配列のコピーがかなり速いことがわかりますか?スニペットの上に欠陥がありますか?それとも、ボトルネックなどになるまで、人々はそれを最適化してはいけませんか?

+1

メモリの割り当てが不要なので、再利用ははるかに高速です。同じことはオブジェクト参照には適用されません。それらを再利用することは、何もしないので、いくらか意味がありません。 –

+2

最後の文の "Or"は間違った選択です。上記のパフォーマンス比較スニペットでは、タイミングの差異がよく見えるかもしれません。ボトルネックになるまで*と*の人々はそれを最適化してはいけません。 – dasblinkenlight

+0

実際に** 2つではなく4つの可能性があります:(再)既存の配列とarraycopyを使用します。既存の配列とfor-assignを使用する。新しい配列とarraycopyをそれに割り当てます( 'Arrays.copyOf'があなたに当てはまります)。新しい配列とfor-assignを割り当てます。パフォーマンスが重要なのは、これが多く行われた場合だけで、JITに十分に対応すればパフォーマンスが変化するということです。また、多くの配列(またはオブジェクト)を割り当てると、実際の使用ではGCの集約コストが増加しますが、1つのアイテムのエフェクトを測定することはできません。マイクロベンチマークではない5000以上の既存の回答が正しい。 –

答えて

3

その配列のコピーが大幅に高速短い を使用してアレイを再作成WRTと比較されるショー上記の性能比較スニペットを缶プリミティブ配列に住んでいましたか?

はい、実際には証明する必要はありません。配列はメモリ内の連続したスペースを占有します。 System.arraycopyはネイティブ関数であり、配列のコピー専用です。ループを終了するかどうかをチェックしたり、プリミティブを配列の特定の位置に割り当てるなど、ループを繰り返すごとにカウンタを増やしたり、配列を作成するよりも高速になることは明らかです。

また、コンパイラは今日はかなりスマートなので、コードをより効率的なものに置き換える可能性があることを忘れないでください。このような場合、あなたが書いたテストの違いは見られません。また、Javaはジャストインタイムコンパイラを使用しています。これは、実行後にコードを最適化する可能性があり、最適化を行う価値があると判断します。

上記のスニペットに欠陥がありますか?

はい、問題があります。あなたがここでやっているのはマイクロベンチマーキングです。ただし、ウォームアップフェーズはまだ完了していません。私はこの話題についてもっと読むことを提案します。

それともボトルネック、 などになるまで、人々はまだそれを最適化するべきではないのですか?

時期尚早な最適化を行うべきではありません。パフォーマンス上の問題がある場合は、プロファイラを有効にしてコードを実行し、ボトルネックを特定して問題を修正します。

しかし、あなたはまた、いくつかの常識を使用する必要があります。 Listがあり、正面に要素を追加している場合はArrayListではなくLinkedListを使用してください。アレイ全体をコピーする必要がある場合は、ループを繰り返す代わりにSystem.arraycopyを使用し、手動で実行してください。

関連する問題