为什么System.arraycopy在Java中是原生的?

时间:2010-05-05 10:01:46

标签: java arrays native arraycopy

我很惊讶地在Java源代码中看到System.arraycopy是一种本机方法。

当然原因是因为它更快。但是什么原生技巧是能够使用的代码使其更快?

为什么不循环遍历原始数组并将每个指针复制到新数组 - 当然这不是那么缓慢和麻烦?

5 个答案:

答案 0 :(得分:73)

在本机代码中,可以使用单个memcpy / memmove完成,而不是 n 不同的复制操作。性能差异很大。

答案 1 :(得分:15)

它不能用Java编写。本机代码能够忽略或忽略Object数组和基元数组之间的差异。 Java无法做到这一点,至少效率不高。

由于重叠数组所需的语义,无法用单个memcpy()编写。

答案 2 :(得分:9)

当然,这取决于实现。

HotSpot会将其视为“内在”并在呼叫站点插入代码。那是机器代码,而不是旧C代码。这也意味着该方法签名的问题很大程度上消失了。

简单的复制循环非常简单,可以对其应用明显的优化。例如循环展开。究竟发生了什么又是依赖于实现的。

答案 3 :(得分:4)

在我自己的测试中,复制多维数组的System.arraycopy()比循环交错快10到20倍:

float[][] foo = mLoadMillionsOfPoints(); // result is a float[1200000][9]
float[][] fooCpy = new float[foo.length][foo[0].length];
long lTime = System.currentTimeMillis();
System.arraycopy(foo, 0, fooCpy, 0, foo.length);
System.out.println("native duration: " + (System.currentTimeMillis() - lTime) + " ms");
lTime = System.currentTimeMillis();

for (int i = 0; i < foo.length; i++)
{
    for (int j = 0; j < foo[0].length; j++)
    {
        fooCpy[i][j] = foo[i][j];
    }
}
System.out.println("System.arraycopy() duration: " + (System.currentTimeMillis() - lTime) + " ms");
for (int i = 0; i < foo.length; i++)
{
    for (int j = 0; j < foo[0].length; j++)
    {
        if (fooCpy[i][j] != foo[i][j])
        {
            System.err.println("ERROR at " + i + ", " + j);
        }
    }
}

打印:

System.arraycopy() duration: 1 ms
loop duration: 16 ms

答案 4 :(得分:3)

有几个原因:

  1. JIT不太可能生成与手动编写的C代码一样高效的低级代码。使用低级别C可以实现许多优化,这些优化对于通用JIT编译器来说几乎是不可能的。

    有关手写C实现的一些技巧和速度比较,请参阅此链接(memcpy,但原理相同):查看此Optimizing Memcpy improves speed

  2. C版本几乎与数组成员的类型和大小无关。在java中不可能这样做,因为无法将数组内容作为原始内存块(例如指针)获取。