
Я наткнулся на статью Нареша Джоши о копировании и клонировании и был удивлён ситуацией с производительностью. У клонирования есть проблемы с финальными полями. А учитывая тот факт, что интерфейс Cloneable не предоставляет метод clone, то для вызова clone вам необходимо будет знать конкретный тип класса.
Вы можете написать такой код:
((Cloneable)o).clone(); // не работаетЕсли интерфейс Cloneable сломан, то у механизма клонирования могут быть некоторые преимущества. При копировании памяти он может оказаться эффективнее, чем копирование поля за полем. Это подчёркивает Джош Блох, автор Effective Java:
Даг Ли пошёл ещё дальше. Он сказал мне, что теперь клонирует только при копировании массивов. Вам следует использовать клонирование копирования массивов, потому что в целом это самый быстрый способ. Но у Дага типы больше не реализуют Cloneable. Он с ним завязал. И я не считаю это необоснованным.Но это было в 2002-м, разве ситуация не изменилась? Со времён Java 6 у нас есть Arrays.copyOf, что насчёт него? Какова производительность копирования объекта?
Есть только один способ выяснить: прогнать бенчмарки.
TL;DR
Клонирование работает быстрее при копировании массива, это заметно на маленьких массивах.- Arrays.copyOf и clone примерно одинаково работают
- Клонирование работает медленнее для маленьких объектов, меньше восьми полей, но в любом случае быстрее.
- При клонировании не работает escape analysis, и потенциально оно может помешать применению других оптимизаций.

Массивы
[UPD]Andrei Paguin указал в комментариях что с бенчмарком есть проблема.
замените “size” на “original.length” в бенчмарке Arrays.copyOf().
И тут я понял, что да… это объясняет почему jit может понять что мы копируем ровно такую же длину. Поэтому я изменил выводы и статью
Давайте быстро рассмотрим clone и 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. Обратите внимание: мы вернули результат копирования, чтобы гарантировать, что код будет выполнен. В главе про escape analysis мы увидим, как невозвращение массива может радикально повлиять на бенчмарк.
Наряду с int array есть версия для byte array, long array и Object array. Я использую флаг DONT_INLINE, чтобы при необходимости легче было анализировать сгенерированный asm.
mvn clean install
java -jar target/benchmark.jar -bm avgt -tu ns -rf csv- здесь будут обновленные результаты —
Объекты
Теперь разберёмся с клонированием объектов с 4, 8, 16 и 32 полями. Бенчмарки ищут объекты с 4 полями:
Комментарии (5)

apangin
27.07.2017 16:53+1Как видите, clone по сравнению с Arrays.copyOf обходится примерно на 10 % дешевле при маленьких массивах
Бенчмарк неправильный, соответственно, и выводы ложные.
Подсказка: в вызовеArrays.copyOfнадо заменитьsizeнаoriginal.length.
apangin
27.07.2017 20:40+2Указал автору оригинальной статьи на ошибку, которую он, к чести, оперативно исправил. Выводы в статье поменялись. Неплохо бы теперь и перевод обновить, чтоб соответствовал новой редакции.

DigitalSmile
27.07.2017 17:28+3Хоть бы написали версию java, я уж не говорю о качестве бенчмарков и выводов на их основе…
izzholtik
Простите, но это нечитаемо. Оригинальная статья — та ещё каша, и бездумный и почти дословный перевод явно не пошёл ей на пользу.