对于小型数组,Java的System.arraycopy()是否有效?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (59)

Java System.arraycopy()对小型数组是否高效,还是它是一个本地方法的事实使它可能比简单循环和函数调用的效率低得多?

原生方法是否会导致跨越某种Java系统桥的额外性能开销?

提问于
用户回答回答于

对于Sid写的内容稍微扩展一点,这很可能System.arraycopy只是JIT的内在特征; 这意味着当代码调用时System.arraycopy,它很可能会调用特定于JIT的实现(一旦JIT标记System.arraycopy为“热”),而不是通过JNI接口执行,所以它不会产生本地方法的正常开销。

一般来说,执行本地方法确实会有一些开销(通过JNI接口,当执行本地方法时也不会发生一些内部JVM操作)。但这并不是因为一个方法被标记为“native”,而是你实际上正在使用JNI执行它。JIT可以做一些疯狂的事情。

如前所述,最简单的检查方法是编写一个小基准,小心Java小基准的正常警告(首先预热代码,避免代码没有副作用,因为JIT只是将其优化为无操作等)。

用户回答回答于

这是我的基准代码:

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;
}

从我的测试中,test()copyCount= 10000000(1e7)或更高的呼叫允许在第一次copy/loop呼叫期间实现预热,所以使用testRep= 5就足够了; 当copyCount= 1000000(1e6)时,预热需要至少2或3次迭代,因此testRep应该增加以获得可用的结果。

使用我的配置(CPU Intel Core 2 Duo E8500 @ 3.16GHz,Java SE 1.6.0_35-b10和Eclipse 3.7.2),从基准测试中可以看出:

  • copySize= 24时,System.arraycopy()手动循环的时间几乎相同(有时一个比另一个快得多,其他时间则相反),
  • copySize<24时,手动循环比System.arraycopy()(快于copySize23时快一点,快于copySize<5时快一点)快一些,
  • copySize> 24时,System.arraycopy()比手动回路快(当copySize= 25时稍快,比率环路时间/阵列复制时间随着增加而copySize增加)。

扫码关注云+社区