Я пытался измерить производительность System.arrayCopy vs Arrays.copyOf, чтобы правильно выбрать один из них. Только ради бенчмарка я также добавил ручную копию, и результат удивил меня. Очевидно, что мне не хватает чего-то действительно важного, не могли бы вы рассказать мне, что это такое? Реализация следующая (см. Первые 4 метода).System.arrayCopy is slow
public class ArrayCopy {
public static int[] createArray(int size) {
int[] array = new int[size];
Random r = new Random();
for (int i = 0; i < size; i++) {
array[i] = r.nextInt();
}
return array;
}
public static int[] copyByArraysCopyOf(int[] array, int size) {
return Arrays.copyOf(array, array.length + size);
}
public static int[] copyByEnlarge(int[] array, int size) {
return enlarge(array, size);
}
public static int[] copyManually(int[] array, int size) {
int[] newArray = new int[array.length + size];
for (int i = 0; i < array.length; i++) {
newArray[i] = array[i];
}
return newArray;
}
private static void copyArray(int[] source, int[] target) {
System.arraycopy(source, 0, target, 0, Math.min(source.length, target.length));
}
private static int[] enlarge(int[] orig, int size) {
int[] newArray = new int[orig.length + size];
copyArray(orig, newArray);
return newArray;
}
public static void main(String... args) {
int[] array = createArray(1000000);
int runs = 1000;
int size = 1000000;
System.out.println("****************** warm up #1 ******************");
warmup(ArrayCopy::copyByArraysCopyOf, array, size, runs);
warmup(ArrayCopy::copyByEnlarge, array, size, runs);
warmup(ArrayCopy::copyManually, array, size, runs);
System.out.println("****************** warm up #2 ******************");
warmup(ArrayCopy::copyByArraysCopyOf, array, size, runs);
warmup(ArrayCopy::copyByEnlarge, array, size, runs);
warmup(ArrayCopy::copyManually, array, size, runs);
System.out.println("********************* test *********************");
System.out.print("copyByArrayCopyOf");
runTest(ArrayCopy::copyByArraysCopyOf, array, size, runs);
System.out.print("copyByEnlarge");
runTest(ArrayCopy::copyByEnlarge, array, size, runs);
System.out.print("copyManually");
runTest(ArrayCopy::copyManually, array, size, runs);
}
private static void warmup(BiConsumer<int[], Integer> consumer, int[] array, int size, int runs) {
for (int i = 0; i < runs; i++) {
consumer.accept(array, size);
}
}
private static void runTest(BiConsumer<int[], Integer> consumer, int[] array, int size, int runs) {
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
long currentCpuTime = threadMXBean.getCurrentThreadCpuTime();
long nanoTime = System.nanoTime();
for (int i = 0; i < runs; i++) {
consumer.accept(array, size);
}
System.out.println("-time = " + ((System.nanoTime() - nanoTime)/10E6) + " ms. CPU time = " + ((threadMXBean.getCurrentThreadCpuTime() - currentCpuTime)/10E6) + " ms");
}
}
Результат показывает, что ручное копирование выполняется около 30% лучше, как показано ниже:
****************** warm up #1 ******************
****************** warm up #2 ******************
********************* test *********************
copyByArrayCopyOf-time = 162.470107 ms. CPU time = 153.125 ms
copyByEnlarge-time = 168.6757949 ms. CPU time = 164.0625 ms
copyManually-time = 116.3975962 ms. CPU time = 110.9375 ms
Я очень смущен, потому что я думал (и, вероятно, я до сих пор), что из-за System.arrayCopy
его nativity является наилучшим способом копирования массива, но я не могу объяснить этот результат.
Я предполагаю, что компилятор перехитрил вас и превратил вашу ручную копию в arraycopy, но без Math.min и без дополнительной функции. Кроме того, возможно, поменяйте порядок пару раз и запишите вызовы GC. – TWT