Naresh Joshiによるコピーとクローン作成に関する記事に出会い、パフォーマンスの状況に驚きました。 クローニングには最終フィールドに問題があります 。 また、 Cloneableインターフェイスがclone
メソッドを提供しないという事実を考えると、 clone
を呼び出すクラスの特定のタイプを知る必要があります。
次のようなコードを書くことができます。
((Cloneable)o).clone(); //
Cloneable
インターフェイスが破損している場合、クローニングメカニズムにはいくつかの利点があります。 メモリをコピーする場合、フィールドごとにコピーするよりも効率的です。 これは、Effective Javaの著者であるJosh Bloch によって強調されています。
ダグ・リーはさらに進んだ。 彼は、アレイをコピーするときにのみクローンを作成するようになったと言いました。 全体としてこれが最速の方法であるため、アレイをコピーするクローンを使用する必要があります。 しかし、Dougでは、型はCloneable
実装しなくなりました。 彼は彼と打ち合った。 そして、これは不合理だとは思いません。
しかし、それは2002年でしたが、状況は変わっていませんか? Java 6以降、 Arrays.copyOf
がありArrays.copyOf
、それについてはどうですか? オブジェクトのコピーのパフォーマンスはどうですか?
見つける方法は1つしかありません。ベンチマークを取り除くことです。
TL; DR
配列をコピーする場合、クローニングはより高速に動作します。これは小さな配列で顕著です。- Arrays.copyOfとcloneはほぼ同じように動作します
- クローンは、8オブジェクト未満の小さなオブジェクトでは遅くなりますが、とにかく速くなります。
- クローンを作成するとき、エスケープ分析は機能せず、潜在的に他の最適化に干渉する可能性があります。
配列
[UPD] Andrei Paguinは、ベンチマークに問題があるとコメントで指摘しました。
ベンチマークのArrays.copyOf()で「size」を「original.length」に置き換えます。
そして、私はそのことに気づきました...これは、jitがまったく同じ長さをコピーしていることを理解できる理由を説明しています。 だから私は結論と記事を変更しました
配列のclone
とArrays.copyOf
をArrays.copyOf
に見てみましょう。
ベンチマーク int array
は次のようになります。
@Benchmark @CompilerControl(CompilerControl.Mode.DONT_INLINE) public int[] testCopy() { return Arrays.copyOf(original, original.length); // size } @Benchmark @CompilerControl(CompilerControl.Mode.DONT_INLINE) public int[] testClone() { return original.clone(); }
ランダムな数値の配列を作成し、 clone
またはArrays.copyOf
。 注:コードが実行されるように、コピー結果を返しました。 エスケープ分析の章では、配列が返されないことがベンチマークに根本的な影響を与えることがわかります。
int array
byte array
、 long array
、およびObject array
バージョンがありbyte array
。 DONT_INLINE
フラグを使用して、必要に応じて生成されたasmを解析しやすくします。
mvn clean install java -jar target/benchmark.jar -bm avgt -tu ns -rf csv
- ここに結果が更新されます-
オブジェクト
次に、4、8、16、および32のフィールドを持つオブジェクトのクローンを作成します。 ベンチマークは、4つのフィールドを持つオブジェクトを探します :