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

10

89

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?

Pritchard answered 7/4, 2010 at 3:0 Comment(3)
What is "Bloch"? Why is the code snippet relevant?Semipalatinsk
@Ciro Bloch is the guy who wrote the ArrayList implementation.Fascia
See also: https://mcmap.net/q/219851/-why-is-arrays-copyof-2-times-faster-than-system-arraycopy-for-small-arrays/14955Assembly
A
120

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;
}
Assembly answered 7/4, 2010 at 3:21 Comment(8)
Its obvious....Arrays.copyOf should create a new instance of array as we are not passing one to it; while we pass a destination to System.arraycopy. Regarding speed, again obviously System.arraycopy should win as it is a native method and ultimately Arrays.copyOf also calls this method for copying an array.Governorship
The Java source doesn't matter since the intrinsic was created.Multiflorous
also System.arraycopy has more detailed parameters, you can specify start index for both arrays.Albumenize
public class TestClass { public static void main(String[] args) { byte a[] = { 65, 66, 67, 68, 69, 70, 71, 72, 73, 74 }; System.arraycopy(a, 0, a, 1, a.length - 1); System.out.println(new String(a)); } }Naturism
code above prints AABCDEFGHI that means it's creating a new array.Naturism
@Rajat Quite the opposite. It changed a in place. As you have shown by printing it.Assembly
@Assembly if it was in place then result would be 10 times ANaturism
Oh, I see what you mean. It updates in place, but of course it can handle the target and source regions overlapping.Assembly
C
46

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 slower 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 the analysis of the previous paragraph:

  1. We are looking at the code from a specific version of Java. These methods may change in future vresions, 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 Why is Arrays.copyOf 2 times faster than System.arraycopy for small arrays?. This method is marked as "intrinsic" in current-generation Java implementations. That means that the JIT compiler may 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. Only worry about which version is faster if profiling of your application tells you that the difference will actually matter.


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.

Cresol answered 7/4, 2010 at 4:15 Comment(6)
+1 for pointing out the type checking that has to take place sometimes.Assembly
@StephenC, Regarding your first paragraph, are there cases where System.arrayCopy could actually be slower?Pryce
@Pryce - I'm not aware of any. But it is not impossible.Cresol
A little late on this response but keeping in mind that System.arrayCopy is referenced by Arrays.copyOf (As is mentioned in the accepted answer) I would have to aruge that it is impossible for System.arrayCopy to be slower. This provided, of course, that it is not a custom implementation of JVM with a custom implementation of the methods.Lapwing
@Lapwing - You are making assumptions about the optimizations that JIT compiler does. It is possible that it is completely ignoring the source code / bytecodes that you are looking at. Or that it might do that in some future version of Java. Or that the source code might be different in some other version. Or that there is some clever optimization that can be done on a direct arraycopy call that can't be done on an indirect call. All of these things are possible ... if not plausible.Cresol
Best explanation so far !!Attainder
T
14

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...

Torch answered 7/4, 2010 at 9:53 Comment(8)
Right, but System.arrayCopy is native as well (and it is dedicated to that task) while clone seem to have to deal with many conditions...Pryce
@Pryce "I don't often use clone... but when I do, I use it on arrays."Torch
I was talking about that .clone() when used on arrays.... In any case, it still returns an Object which must then be casted back into an array (= additional work).Pryce
@Pryce actually it's overloaded with the correct return type for all array types, so you don't have to do any casting yourself, and it's not certain the VM will have to check any casts.Torch
Good point, so you are saying that native clone() will be faster than native System.arrayCopy because clone() is dedicated to this task as well?Pryce
@Pryce Well, since clone is more specialized than System.arrayCopy, there's more room for optimizing (for example, you don't need to do any bounds checking). This is not the same as saying it will be faster (for example, S.aC is more widely used and so there is more incentive for the VM writers to improve it).Torch
Anywho, the reason for using clone is not speed, but simplicity - you don't have to remember the parameter order of S.aC, and there'll be no off-by-one errors, etc. As for performance, the difference is bound to be negligible, or maybe even unmeasurable, for as good as all applications (and when it does matter, perhaps you shouldn't copy an array at all?).Torch
Simplicity may be an added advantage, but the question on top is asking specifically about performance, which means that these functions would be located somewhere deep inside a library employing facade pattern, thus being equally "simple to use".Pryce
P
13

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

Powwow answered 7/4, 2010 at 3:8 Comment(3)
But System.arraycopy only copies into an existing array. Arrays.copyOf also creates the output array for you.Assembly
That's true, and so long as you're using System.arraycopy under the covers whatever convenience wrapper you use is just gravy.Powwow
And, there are cases where System.arrayCopy can't use a direct memory copy.Cresol
G
12

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.

Gudren answered 7/4, 2010 at 10:25 Comment(0)
A
2

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

Auklet answered 7/4, 2010 at 3:17 Comment(1)
Just because it uses native code via JNI, it does not mean that it will be faster: javaspecialists.eu/archive/Issue124.htmlKareenkarel
H
2

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

Haynes answered 23/2, 2018 at 21:8 Comment(2)
Not sure why the downvote, this was relevant and useful to the discussion.Haynes
I would guess, because you did not mention your JDK, OS, HW and did not publish your source-code in order to validate it.Longford
P
1

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!

Predominate answered 17/2, 2021 at 4:13 Comment(0)
E
0

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.

Empyreal answered 26/12, 2018 at 23:49 Comment(1)
Not true -- copyOf is overloaded with a method for each primitive type.Boilermaker
M
-1
      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));
}
 }
Manipulator answered 23/10, 2013 at 5:48 Comment(1)
This doesn't answer the question.Cresol

© 2022 - 2024 — McMap. All rights reserved.