Is it better to use System.arraycopy(…) than a for loop for copying arrays?

前端 未结 7 1655
离开以前
离开以前 2020-11-28 20:28

I want to create a new array of objects putting together two smaller arrays.

They can\'t be null, but size may be 0.

I can\'t chose between these two ways: a

相关标签:
7条回答
  • 2020-11-28 21:03

    It depends on the virtual machine, but System.arraycopy should give you the closest you can get to native performance.

    I've worked for 2 years as a java developer for embedded systems (where performance is a huge priority) and everywhere System.arraycopy could be used, I've mostly used it / seen it used in existing code. It's always preferred over loops when performance is an issue. If performance isn't a big issue, I'd go with the loop, though. Much easier to read.

    0 讨论(0)
  • 2020-11-28 21:04

    Arrays.copyOf(T[], int) is easier to read. Internaly it uses System.arraycopy() which is a native call.

    You can't get it faster!

    0 讨论(0)
  • 2020-11-28 21:07

    It is not possible that Arrays.copyOf is faster than System.arraycopy since this is the implementation of copyOf:

    public static int[] copyOf(int[] original, int newLength) {
        int[] copy = new int[newLength];
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }
    
    0 讨论(0)
  • 2020-11-28 21:15

    System.arraycopy() is a native call which does copy operation directly at memory. Single memory copy would be always faster than your for loop

    0 讨论(0)
  • 2020-11-28 21:18
    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);
    }
    

    I know JUnit tests aren't really the best for benchmarking, but
    testHardCopyBytes took 0.157s to complete
    and
    testArrayCopyBytes took 0.086s to complete.

    I think it depends on the virtual machine, but it looks as if it copies blocks of memory instead of copying single array elements. This would absolutely increase performance.

    EDIT:
    It looks like System.arraycopy 's performance is all over the place. When Strings are used instead of bytes, and arrays are small (size 10), I get these results:

        String HC:  60306 ns
        String AC:  4812 ns
        byte HC:    4490 ns
        byte AC:    9945 ns
    

    Here is what it looks like when arrays are at size 0x1000000. It looks like System.arraycopy definitely wins with larger arrays.

        Strs HC:  51730575 ns
        Strs AC:  24033154 ns
        Bytes HC: 28521827 ns
        Bytes AC: 5264961 ns
    

    How peculiar!

    Thanks, Daren, for pointing out that references copy differently. It made this a much more interesting problem!

    0 讨论(0)
  • 2020-11-28 21:24

    Executing native methods like Arrays.copyOf(T[], int) does have some overhead but it doesnot mean that it is not fast as you are executing it using JNI.

    The easiest way is to write a benchmark and test.

    You can check that Arrays.copyOf(T[], int) is faster than your normal for loop.

    The benchmark code from 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() uses JNI (Java Native Interface) to copy an array (or parts of it), so it is blazingly fast, as you can confirm here

    0 讨论(0)
提交回复
热议问题