What is more efficient: System.arraycopy or Arrays.copyOf?

JavaArraysPerformance

Java Problem Overview


The toArray method in ArrayList, Bloch uses both System.arraycopy and Arrays.copyOf to copy an array.

public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

How can I compare these two copy methods and when should I use which?

Java Solutions


Solution 1 - Java

The difference is that Arrays.copyOf does not only copy elements, it also creates a new array. System.arraycopy copies into an existing array.

Here is the source for Arrays.copyOf, as you can see it uses System.arraycopy internally to fill up the new array:

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
    T[] copy = ((Object)newType == (Object)Object[].class)
        ? (T[]) new Object[newLength]
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);
    System.arraycopy(original, 0, copy, 0,
                     Math.min(original.length, newLength));
    return copy;
}

Solution 2 - Java

While System.arraycopy is implemented natively, and is therefore could be1 faster than a Java loop, it is not always as fast as you might expect. Consider this example:

Object[] foo = new Object[]{...};
String[] bar = new String[foo.length];

System.arraycopy(foo, 0, bar, 0, bar.length);

In this case, the foo and bar arrays have different base types, so the implementation of arraycopy has to check the type of every reference copied to make sure that it is actually a reference to a String instance. That is significantly slower than a simple C-style memcopy of the array contents.

The other point is that Arrays.copyOf uses System.arraycopy under the hood. Therefore System.arraycopy is on the face of it should not be slower2 than Arrays.copyOf. But you can see (from the code quoted above) that Arrays.copyOf will in some cases use reflection to create the new array. So the performance comparison is not straightforward.

There are a couple of flaws in this analysis.

  1. We are looking at the implementation code from a specific version of Java. These methods may change, invalidating previous assumptions about efficiency.

  2. We are ignoring the possibility that the JIT compiler could do some clever special case optimization for these methods. And it apparently this does happen with Arrays.copyOf; see https://stackoverflow.com/questions/44487304/why-is-arrays-copyof-2-times-faster-than-system-arraycopy-for-small-arrays. This method is "intrinsic" in current-generation Java implementations, which means that the JIT compiler will ignore what is in the Java source code!

But either way, the difference between the two versions is O(1) (i.e. independent of array size) and relatively small. Therefore, my advice would be to use the version that makes your code easiest to read, and only worry about which one is faster if profiling tells you that it matters.


1 - It could be faster, but it is also possible that the JIT compiler does such a good job of optimizing a hand-coded loop that there is no difference.

Solution 3 - Java

If you want an exact copy of an array (say, if you want to do a defensive copy), the most effective way of copying an array is probably using the array object's clone() method:

class C {
    private int[] arr;
    public C(int[] values){
        this.arr = values.clone();
    }
}

I haven't bothered to test the performance of it, but it stands a good chance to be pretty fast since it's all native (allocation and copying in call), and cloning is kind of a special JVM blessed way of copying objects (and it's mostly evil for other purposes) and is likely to be able to take some "shortcuts".

Personally, I'd still use clone if it was slower than any other way of copying, because it's easier to read and nigh-impossible to screw up when writing. System.arrayCopy, on the other hand...

Solution 4 - Java

System.arrayCopy is much faster. It's in system because it uses a direct memory copy outside of Java land. Use it when possible.

Solution 5 - Java

Have you looked at the Sun's implementation of Arrays.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;
}

As can be seen, it uses System.arraycopy() internally, so the performance would be the same.

Solution 6 - Java

System.arrayCopy is implemented natively, and hence will be faster than any Java code. I recommend you to use it.

Solution 7 - Java

Instead of debating, these are the actual results. Clearly, your choice will depend on how much data you want to copy.

byte[] copy performance test

10,000,000 iterations 40b array.copyOfRange: 135ms systems.arraycopy: 141ms

10,000,000 iterations 1000b array.copyOfRange: 1861ms systems.arraycopy: 2211ms

10,000,000 iterations 4000b array.copyOfRange: 6315ms systems.arraycopy: 5251ms

1,000,000 iterations 100,000b array.copyOfRange: 15,198ms systems.arraycopy: 14783ms

Solution 8 - Java

I posted this on another answer but may be useful here as well.

I know this is not definitive by any means, as benchmarking these kinds of operations is a science on its own, but just for the fun, I made some tests to compare System.arraycopy and Arrays.copyOfRange.

  • Base array is a String[] array, filled with nulls. The size of the array goes from 10 million to 100 million elements.

  • The array is split 24 times.

  • The elapsed time shows the best time from 3 different launches for each base size.

enter image description here

I don't believe there's enough difference in order to conclude that arraycopy is faster in any way. Also, in order to be complete, the test should also include different split sizes (other than 24), as well as other data types and value-filled arrays (other than null).

Test it online (I tested it locally, but may be useful).


Test code

Common block:

 String[] a = new String[baseSize]; // f.e - 10.000.000
 int size = baseSize / 24;
 int rem = baseSize % 24;

And for each method:

System.arraycopy

 long start = System.currentTimeMillis();
 
 String[][]pieces = new String[23][size];
 String[] last = new String[size + rem];   
 for (int i = 0; i < 23; i++)
    System.arraycopy(a, (size * i), pieces[i], 0 , size); 
 System.arraycopy(a, (size * 23), last, 0 ,(size) + rem); 

 long elapsed = System.currentTimeMillis() - start;

Arrays.copyOfRange

 long start = System.currentTimeMillis();

 String[][] pieces = new String[23][];
 for (int i = 0; i < 23; i++)
   	pieces[i] = Arrays.copyOfRange(a, size * i, size * (i + 1)); 
 String[] last = Arrays.copyOfRange(a, size * 23, (size * 24) + rem);

 long elapsed = System.currentTimeMillis() - start;

The code is easily configurable, so feel free to play with the total pieces to split into, data types, filled arrays and so on. Have fun!

Solution 9 - Java

If you look at both the source code for System.arraycopy() of and Array.copyOf(), for performance.

System.arraycopy() is C code, it operates directly on your array, it does not return any values, and because of that it should operate much faster than Array.copyOf(). Nonetheless, if you need a new array to be created or if you just need the value of the copy operation then you have to create a new array for that, set the new array length, etc... Thus, you can't do a return System.arraycopy(source, 0, destination, 0, length).

For what Array.copyOf() can do then, it make a new array for you. You can assign the return value from Array.copyOf() to an array or returning it from a method as Array.copyOf() return to you a value instead of operating directly on your destination array. Thus, your code will look much cleaner. Nonetheless, for the cost of performance, Array.copyOf() is a generic type method and it does not know ahead of time what it will be working with. Thus, it has to call Array.newInstance() or new Object() and then cast it to the input's array type.

So to sum up. Use System.arraycopy() because of performance. Use Array.copyOf() for cleaner code.

Solution 10 - Java

      class ArrayCopyDemo {
   public static void main(String[] args) {
    char[] copyFrom = { 'd', 'e', 'c', 'a', 'f', 'f', 'e',
		    'i', 'n', 'a', 't', 'e', 'd' };
    char[] copyTo = new char[7];

    System.arraycopy(copyFrom, 2, copyTo, 0, 7);
    System.out.println(new String(copyTo));
}
 }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionSawyerView Question on Stackoverflow
Solution 1 - JavaThiloView Answer on Stackoverflow
Solution 2 - JavaStephen CView Answer on Stackoverflow
Solution 3 - JavagustafcView Answer on Stackoverflow
Solution 4 - JavaRy4an BraseView Answer on Stackoverflow
Solution 5 - JavamatsevView Answer on Stackoverflow
Solution 6 - JavaHumphrey BogartView Answer on Stackoverflow
Solution 7 - JavacyberthreatView Answer on Stackoverflow
Solution 8 - JavaaranView Answer on Stackoverflow
Solution 9 - JavaKevin NgView Answer on Stackoverflow
Solution 10 - JavaAmbikaView Answer on Stackoverflow