我一直在尝试测量System.arrayCopy与Arrays.copyOf的性能,以便正确选择其中的一个。只是为了基准,我添加了手册,结果令我感到惊讶。 显然我错过了一些非常重要的东西,请问,请告诉我,它是什么?实施如下(见前4种方法)。System.arrayCopy很慢
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
由于它的诞生是复制数组的最佳方法,但我无法解释这个结果。
我猜测编译器超过了你,并且把你的手动拷贝变成了一个arraycopy,但没有Math.min,也没有额外的函数间接寻址。此外,也许可以交换订单几次并记录GC呼叫。 – TWT