Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/373.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么克隆阵列这么慢?_Java_Performance_Clone - Fatal编程技术网

Java 为什么克隆阵列这么慢?

Java 为什么克隆阵列这么慢?,java,performance,clone,Java,Performance,Clone,这个测试 for (;;) { int[] a = new int[10]; System.gc(); long t0 = System.currentTimeMillis(); for (int i = 0; i < 1000000; i++) { // int[] b = a.clone(); int[] b =

这个测试

        for (;;) {
            int[] a = new int[10];
            System.gc();
            long t0 = System.currentTimeMillis();
            for (int i = 0; i < 1000000; i++) {
//              int[] b =  a.clone();
                int[] b =  Arrays.copyOf(a, a.length);
            }
            System.out.println(System.currentTimeMillis() - t0);
        }
(;;)的
{
int[]a=新的int[10];
gc();
长t0=System.currentTimeMillis();
对于(int i=0;i<1000000;i++){
//int[]b=a.clone();
int[]b=Arrays.copyOf(a,a.length);
}
System.out.println(System.currentTimeMillis()-t0);
}
Arrays.copyOf显示约50毫秒,clone显示约160毫秒。克隆是一种特殊的本地复制方法,为什么它这么慢


我在HotSpot客户端JVM1.7.0_11-b21上运行了测试。请注意,当阵列的大小增加时,克隆和复制之间的差异消失。

我在我的系统上运行了您的代码:它们之间几乎没有差异。两个时钟都在30毫秒左右。我的测试是在OpenJDK 7上进行的

为了证实这一点,我还通过卡尺进行了测试,并使用了更大的阵列来强调实际的复制性能:

public class Performance extends SimpleBenchmark {
  final int[] source = new int[1000];

  public int timeClone(int reps) {
    int sum = 0;
    for (int i = reps; i > 0; i--)
      sum += source.clone().length;
    return sum;
  }

  public int timeCopyOf(int reps) {
    int sum = 0;
    for (int i = reps; i > 0; i--)
      sum += Arrays.copyOf(source,source.length).length;
    return sum;
  }
  public static void main(String... args) {
    Runner.main(Performance.class, args);
  }
}
结果:

 0% Scenario{vm=java, trial=0, benchmark=Clone} 2141.70 ns; σ=5416.80 ns @ 10 trials
50% Scenario{vm=java, trial=0, benchmark=CopyOf} 2168.38 ns; σ=1545.85 ns @ 10 trials

benchmark   us linear runtime
    Clone 2.14 =============================
   CopyOf 2.17 ==============================

vm: java
trial: 0
根据请求,这里是阵列大小为10的:

 0% Scenario{vm=java, trial=0, benchmark=Clone} 30.07 ns; σ=2.12 ns @ 10 trials
50% Scenario{vm=java, trial=0, benchmark=CopyOf} 29.34 ns; σ=161.38 ns @ 10 trials

benchmark   ns linear runtime
    Clone 30.1 ==============================
   CopyOf 29.3 =============================

我发现了一篇很好的文章,解释了为什么克隆在这里很慢。简而言之,这是因为int[].clone只使用Object.clone,此方法在复制阵列之前进行两次检查:

1.检查实例是普通对象还是数组

2.检查数组是基元数组还是对象数组

我将这些检查添加到Arrrays.copyOf测试中

        for (int i = 0; i < 1000000; i++) {
            Class cls = a.getClass();
            if (cls.isArray() && !cls.getComponentType().isAssignableFrom(Object.class)) {
                int[] b = Arrays.copyOf(a, a.length);
            }
        }
for(int i=0;i<1000000;i++){
类cls=a.getClass();
if(cls.isArray()&&!cls.getComponentType().isAssignableFrom(Object.class)){
int[]b=Arrays.copyOf(a,a.length);
}
}

测试显示克隆和数组之间没有差异。如果它是用于阵列的专用版本,克隆会很快。

clone
过载(因为它必须同时处理指针和标量阵列),并且在标准Sun/Oracle实现中,可能未进行优化。我曾经研究过
clone
的实现,这肯定会做得更好。还请注意,如果使用较大的数组(比如10000个元素),则数字可能会有所不同。下面是对您解释的一个bug的引用:--无论您的微基准多么糟糕-这显然是错误的,存在这种可能性,编译器将删除完整的循环。克隆的数组指向未使用的局部变量。我不确定字节码是否会包含该循环。我在HotSpot客户端JVM1.7.011上运行了测试-b21@ChristianKuetbachHotSpot不敢消除整个方法调用,因为它可能有副作用。@Marko你能在数组大小为10的情况下重新运行测试吗?这里有一些证据,无需测试:
a)
那篇文章是关于Java 1.5的,是2006年的
b)
即使考虑到他们的发现,也要注意他们的结论:与
new
+
arraycopy
相比,更喜欢
clone
,因为代码更简单,复制性能相同。两个简单的
if
检查不可能导致任何实际代码的性能下降。