我很惊讶在Java源代码中看到System.arraycopy是本机方法。
当然,原因是因为它速度更快。但是,能够采用哪些本机技巧使代码更快呢?
为什么不只是循环遍历原始数组并将每个指针复制到新数组-当然这不是那么慢且麻烦吗?
Answers:
在本机代码中,可以使用单个memcpy
/来完成,这与n个不同的复制操作memmove
相反。性能差异很大。
arraycopy
使用memcpy
/来实现的某些子情况memmove
。其他要求对复制的每个元素进行运行时类型检查。
它不能用Java编写。本机代码能够忽略或消除Object数组与基本数组之间的差异。Java无法做到这一点,至少没有效率。
而且,由于重叠数组需要语义,因此不能用单个memcpy()
语言编写。
memmove
那就这样。尽管我认为在此问题的上下文中并没有多大区别。
在我自己的测试中,用于复制多维数组的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
System.arraycopy
执行浅表复制(仅复制对内部s的引用float[]
),而您的嵌套for
-loops执行深表复制(float
by float
)。对的更改fooCpy[i][j]
将在foo
using中反映出来System.arraycopy
,但不会使用嵌套的for
-loops。
有几个原因:
JIT不太可能像手动编写的C代码那样生成高效的低级代码。使用低级C可以实现很多优化,而这些优化对于通用JIT编译器几乎是不可能的。
请参见此链接,以了解一些手写C实现的技巧和速度比较(memcpy,但原理相同):选中此优化Memcpy可以提高速度
C版本几乎与数组成员的类型和大小无关。在Java中不可能做同样的事情,因为没有办法将数组内容作为原始的内存块(例如指针)获取。