2017-06-11 15 views
5

私は最近、いくつかのベンチマークで遊んでいて、今説明できない非常に興味深い結果を発見しました。ここでは、ベンチマークは次のとおりです。Arrays.copyOfはSystem.arraycopyよりも2倍高速に配列されていますか?

@BenchmarkMode(Mode.Throughput) 
@Fork(1) 
@State(Scope.Thread) 
@Warmup(iterations = 10, time = 1, batchSize = 1000) 
@Measurement(iterations = 10, time = 1, batchSize = 1000) 
public class ArrayCopy { 

    @Param({"1","5","10","100", "1000"}) 
    private int size; 
    private int[] ar; 

    @Setup 
    public void setup() { 
     ar = new int[size]; 
     for (int i = 0; i < size; i++) { 
      ar[i] = i; 
     } 
    } 

    @Benchmark 
    public int[] SystemArrayCopy() { 
     final int length = size; 
     int[] result = new int[length]; 
     System.arraycopy(ar, 0, result, 0, length); 
     return result; 
    } 

    @Benchmark 
    public int[] javaArrayCopy() { 
     final int length = size; 
     int[] result = new int[length]; 
     for (int i = 0; i < length; i++) { 
      result[i] = ar[i]; 
     } 
     return result; 
    } 

    @Benchmark 
    public int[] arraysCopyOf() { 
     final int length = size; 
     return Arrays.copyOf(ar, length); 
    } 

} 

結果:

Benchmark     (size) Mode Cnt  Score  Error Units 
ArrayCopy.SystemArrayCopy  1 thrpt 10 52533.503 ± 2938.553 ops/s 
ArrayCopy.SystemArrayCopy  5 thrpt 10 52518.875 ± 4973.229 ops/s 
ArrayCopy.SystemArrayCopy  10 thrpt 10 53527.400 ± 4291.669 ops/s 
ArrayCopy.SystemArrayCopy  100 thrpt 10 18948.334 ± 929.156 ops/s 
ArrayCopy.SystemArrayCopy 1000 thrpt 10 2782.739 ± 184.484 ops/s 
ArrayCopy.arraysCopyOf   1 thrpt 10 111665.763 ± 8928.007 ops/s 
ArrayCopy.arraysCopyOf   5 thrpt 10 97358.978 ± 5457.597 ops/s 
ArrayCopy.arraysCopyOf   10 thrpt 10 93523.975 ± 9282.989 ops/s 
ArrayCopy.arraysCopyOf  100 thrpt 10 19716.960 ± 728.051 ops/s 
ArrayCopy.arraysCopyOf  1000 thrpt 10 1897.061 ± 242.788 ops/s 
ArrayCopy.javaArrayCopy   1 thrpt 10 58053.872 ± 4955.749 ops/s 
ArrayCopy.javaArrayCopy   5 thrpt 10 49708.647 ± 3579.826 ops/s 
ArrayCopy.javaArrayCopy  10 thrpt 10 48111.857 ± 4603.024 ops/s 
ArrayCopy.javaArrayCopy  100 thrpt 10 18768.866 ± 445.238 ops/s 
ArrayCopy.javaArrayCopy  1000 thrpt 10 2462.207 ± 126.549 ops/s 

だからここ2奇妙なことがあります。

  • Arrays.copyOfが小さい アレイ用の2倍System.arraycopyよりも高速ですが(1,5 、10サイズ)。しかし、サイズの大きな配列では、 Arrays.copyOfはほぼ2倍遅くなります。私は両方の メソッドがintrinsicsであることを知っているので、私は同じパフォーマンスが期待されます。この違いは ですか?
  • 1要素配列の手動コピーは、System.arraycopyよりも高速です。なぜ私には分かりません。誰か知っていますか?

VMのバージョン:JDK 1.8.0_131は、VM 25.131-B11

+2

'copyOf'は内部的に' arraycopy'を使用しているので、あなたのベンチマークが問題です。 – Andreas

+2

@アンドレアスあなたは正しくありません。 'Arrays.copyOf'はJVMの組み込みです。メソッドがJITコンパイルされると、 'Arrays.java'のJavaコードはまったく実行されません。 – apangin

+0

@Andreasベンチマークの特有の問題はありますか?一般的なベンチマークの落とし穴を避けるために、[JMH framework](http://openjdk.java.net/projects/code-tools/jmh/)を賢明に使用します。 – apangin

答えて

3

あなたSystemArrayCopyベンチマークは意味的にarraysCopyOfと同等ではありません。あなたは、両方のベンチマークのパフォーマンスも同様になります。この変更に伴い

System.arraycopy(ar, 0, result, 0, Math.min(ar.length, length)); 

System.arraycopy(ar, 0, result, 0, length); 

を交換する場合

それは、となります。

なぜ最初の変異が遅いのですか? lengthar.lengthにJVMをどのように関係するか知らず

  1. は、追加の境界チェックとIndexOutOfBoundsExceptionときlength > ar.lengthを投げるために準備する実行する必要があります。
  2. これはまた、冗長ゼロを除去するために最適化を破ります。ご存知のように、割り当てられた配列はすべてゼロで初期化する必要があります。ただし、作成直後に配列が埋め込まれていることがわかると、JITはゼロになることを避けることができます。しかし-prof perfasmは明らかに、元SystemArrayCopyベンチマークが割り当てられた配列をクリアするかなりの時間を費やしていることを示していますSystem.arraycopyとは異なり、それはVM機能に任意のランタイム呼び出しを実行していないため

    0,84% 0x000000000365d35f: shr $0x3,%rcx 
    0,06% 0x000000000365d363: add $0xfffffffffffffffe,%rcx 
    0,69% 0x000000000365d367: xor %rax,%rax 
          0x000000000365d36a: shl $0x3,%rcx 
    21,02% 0x000000000365d36e: rep rex.W stos %al,%es:(%rdi) ;*newarray 
    

マニュアルコピー、小さなアレイ用速く登場。

+1

'ar.length'と' length'は同じではありませんか? 'Math.min(ar.length、length)'にはどのような影響がありますか? – Boann

+0

@Boann彼らは同じですが、JVMはこれを知らない。 'Math.min'は' System.arraycopy'が決して 'IndexOutOfBoundsException'を投げないことをコンパイラに知らせます。 – apangin

+0

説明してください。コンパイラは、名前、呼び出し順序、結果、 'throws'節(実際には持っていない)以外の地面の穴から' System.arraycopy() 'を知りません。 'System.arraycopy()'は第5引数の 'Math.min()'の結果を受け取り、それがどのように導出されたのか分かりません。 – EJP

関連する問題