我很惊讶地在Java源代码中看到System.arraycopy是一种本机方法。
当然原因是因为它更快。但是什么原生技巧是能够使用的代码使其更快?
为什么不循环遍历原始数组并将每个指针复制到新数组 - 当然这不是那么缓慢和麻烦?
答案 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)
有几个原因:
JIT不太可能生成与手动编写的C代码一样高效的低级代码。使用低级别C可以实现许多优化,这些优化对于通用JIT编译器来说几乎是不可能的。
有关手写C实现的一些技巧和速度比较,请参阅此链接(memcpy,但原理相同):查看此Optimizing Memcpy improves speed
C版本几乎与数组成员的类型和大小无关。在java中不可能这样做,因为无法将数组内容作为原始内存块(例如指针)获取。