我想创建一个新的对象数组,将两个较小的数组放在一起。
它们不能为空,但大小可能为0.
我不能在这两种方式之间做出选择:它们是等效还是效率更高(例如system.arraycopy()复制整个块)?
MyObject[] things = new MyObject[publicThings.length+privateThings.length];
System.arraycopy(publicThings, 0, things, 0, publicThings.length);
System.arraycopy(privateThings, 0, things, publicThings.length, privateThings.length);
或
MyObject[] things = new MyObject[publicThings.length+privateThings.length];
for (int i = 0; i < things.length; i++) {
if (i<publicThings.length){
things[i] = publicThings[i]
} else {
things[i] = privateThings[i-publicThings.length]
}
}
代码外观的唯一区别是什么?
编辑:感谢关联的问题,但它们似乎有一个未解决的讨论:
如果it is not for native types
:byte [],Object [],char []真的更快吗?在所有其他情况下,执行类型检查,这将是我的情况,因此将是等同的......不?
在另一个相关问题上,他们说the size matters a lot
,大小&gt; 24 system.arraycopy()获胜,小于10,手动循环更好...
现在我真的很困惑。
答案 0 :(得分:81)
public void testHardCopyBytes()
{
byte[] bytes = new byte[0x5000000]; /*~83mb buffer*/
byte[] out = new byte[bytes.length];
for(int i = 0; i < out.length; i++)
{
out[i] = bytes[i];
}
}
public void testArrayCopyBytes()
{
byte[] bytes = new byte[0x5000000]; /*~83mb buffer*/
byte[] out = new byte[bytes.length];
System.arraycopy(bytes, 0, out, 0, out.length);
}
我知道JUnit测试不是最适合基准测试的,但是
testHardCopyBytes需要0.157秒才能完成
和
testArrayCopyBytes需要0.086秒才能完成
我认为这取决于虚拟机,但它看起来好像是复制内存块而不是复制单个数组元素。这绝对会提高性能。
编辑:
看起来System.arraycopy的性能已经到处都是。
当使用字符串而不是字节,并且数组很小(大小为10)时,
我得到了这些结果:
String HC: 60306 ns
String AC: 4812 ns
byte HC: 4490 ns
byte AC: 9945 ns
这是数组大小为0x1000000时的样子。看起来System.arraycopy肯定会赢得更大的数组。
Strs HC: 51730575 ns
Strs AC: 24033154 ns
Bytes HC: 28521827 ns
Bytes AC: 5264961 ns
多么奇特!
谢谢,达人,指出参考文献的复制方式不同。这使得这个问题变得更加有趣!
答案 1 :(得分:36)
Arrays.copyOf(T[], int)
更容易阅读。
Internaly它使用System.arraycopy()
这是本机调用。
你无法加快速度!
答案 2 :(得分:15)
这取决于虚拟机,但System.arraycopy应该为您提供最接近本机性能的功能。
我作为嵌入式系统的Java开发人员已经工作了2年(性能是一个非常重要的优先事项),并且可以使用System.arraycopy,我主要使用它/看到它在现有代码中使用。当性能成为问题时,它始终优先于循环。 如果性能不是一个大问题,我会选择循环。更容易阅读。
答案 3 :(得分:8)
我没有依赖猜测和可能过时的信息,而是使用caliper运行了一些基准测试。事实上,Caliper附带了一些例子,其中包括一个CopyArrayBenchmark
来测量这个问题!你所要做的就是运行
mvn exec:java -Dexec.mainClass=com.google.caliper.runner.CaliperMain -Dexec.args=examples.CopyArrayBenchmark
我的结果基于Oracle的Java HotSpot(TM)64位服务器VM,1.8.0_31-b13,运行于2010年中期的MacBook Pro(带有Intel Arrandale i7的macOS 10.11.6,8 GiB RAM)。我不相信发布原始时序数据是有用的。相反,我将用支持的可视化来总结结论。
总结:
for
循环以将每个元素复制到新实例化的数组中,无论是对于短数组还是长数组,都是绝对有利的。 Arrays.copyOf(array, array.length)
和array.clone()
一直都很快。这两种技术的性能几乎相同;你选择哪一个是品味问题。System.arraycopy(src, 0, dest, 0, src.length)
几乎与Arrays.copyOf(array, array.length)
和array.clone()
一样快,但不是那么一致。 (请参阅50000 int
s的情况。)由于这一点以及通话的详细程度,如果您需要精确控制哪些元素被复制到哪里,我建议System.arraycopy()
。以下是时序图:
答案 4 :(得分:6)
执行像Arrays.copyOf(T[], int)
这样的本机方法确实有一些开销,但并不意味着它在使用JNI执行它时速度不快。
最简单的方法是编写基准测试。
您可以检查Arrays.copyOf(T[], int)
是否比正常for
循环更快。
来自here的基准代码: -
public void test(int copySize, int copyCount, int testRep) {
System.out.println("Copy size = " + copySize);
System.out.println("Copy count = " + copyCount);
System.out.println();
for (int i = testRep; i > 0; --i) {
copy(copySize, copyCount);
loop(copySize, copyCount);
}
System.out.println();
}
public void copy(int copySize, int copyCount) {
int[] src = newSrc(copySize + 1);
int[] dst = new int[copySize + 1];
long begin = System.nanoTime();
for (int count = copyCount; count > 0; --count) {
System.arraycopy(src, 1, dst, 0, copySize);
dst[copySize] = src[copySize] + 1;
System.arraycopy(dst, 0, src, 0, copySize);
src[copySize] = dst[copySize];
}
long end = System.nanoTime();
System.out.println("Arraycopy: " + (end - begin) / 1e9 + " s");
}
public void loop(int copySize, int copyCount) {
int[] src = newSrc(copySize + 1);
int[] dst = new int[copySize + 1];
long begin = System.nanoTime();
for (int count = copyCount; count > 0; --count) {
for (int i = copySize - 1; i >= 0; --i) {
dst[i] = src[i + 1];
}
dst[copySize] = src[copySize] + 1;
for (int i = copySize - 1; i >= 0; --i) {
src[i] = dst[i];
}
src[copySize] = dst[copySize];
}
long end = System.nanoTime();
System.out.println("Man. loop: " + (end - begin) / 1e9 + " s");
}
public int[] newSrc(int arraySize) {
int[] src = new int[arraySize];
for (int i = arraySize - 1; i >= 0; --i) {
src[i] = i;
}
return src;
}
System.arraycopy()
使用JNI(Java Native Interface)复制数组(或部分数组),因此速度非常快,因为您可以确认here
答案 5 :(得分:4)
System.arraycopy()
是本机调用,它直接在内存中复制操作。单个内存副本总是比你的for循环快