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?

0xCursor
  • 2,242
  • 4
  • 15
  • 33
Sawyer
  • 15,581
  • 27
  • 88
  • 124

10 Answers10

118

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;
}
0xCursor
  • 2,242
  • 4
  • 15
  • 33
Thilo
  • 257,207
  • 101
  • 511
  • 656
  • 2
    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. – Pravat Panda Jul 24 '16 at 14:58
  • 4
    The Java source [doesn't matter](https://stackoverflow.com/questions/44487304/why-arrays-copyof-is-2-times-faster-than-system-arraycopy-for-small-arrays#comment75970318_44487304) since the intrinsic was created. – maaartinus Jun 11 '17 at 20:10
  • also `System.arraycopy` has more detailed parameters, you can specify start index for both arrays. – M.kazem Akhgary Nov 25 '18 at 16:25
  • 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)); } } – Rajat Jan 13 '20 at 09:27
  • code above prints AABCDEFGHI that means it's creating a new array. – Rajat Jan 13 '20 at 09:28
  • @Rajat Quite the opposite. It changed `a` in place. As you have shown by printing it. – Thilo Jan 13 '20 at 09:56
  • @Thilo if it was in place then result would be 10 times A – Rajat Jan 13 '20 at 10:31
  • Oh, I see what you mean. It updates in place, but of course it can handle the target and source regions overlapping. – Thilo Jan 13 '20 at 10:43
45

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

Naman
  • 27,789
  • 26
  • 218
  • 353
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • 1
    +1 for pointing out the type checking that has to take place sometimes. – Thilo Apr 07 '10 at 06:43
  • @StephenC, Regarding your first paragraph, are there cases where `System.arrayCopy` could actually be *slower*? – Pacerier Aug 18 '14 at 02:50
  • @Pacerier - I'm not aware of any. But it is not impossible. – Stephen C Aug 18 '14 at 05:28
  • 1
    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. – Wayne Apr 07 '16 at 13:08
  • @Wayne - 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. – Stephen C Oct 24 '19 at 01:38
  • Best explanation so far !! – Anish B. Sep 06 '20 at 07:19
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...

gustafc
  • 28,465
  • 7
  • 73
  • 99
  • 1
    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*... – Pacerier Aug 18 '14 at 02:55
  • @Pacerier "I don't often use `clone`... but when I do, I use it on arrays." – gustafc Aug 18 '14 at 07:16
  • 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). – Pacerier Aug 18 '14 at 07:27
  • @Pacerier 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. – gustafc Aug 18 '14 at 10:11
  • 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? – Pacerier Aug 18 '14 at 13:16
  • @Pacerier 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). – gustafc Aug 18 '14 at 14:16
  • 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?). – gustafc Aug 18 '14 at 14:20
  • 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". – Pacerier Aug 18 '14 at 15:15
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.

Ry4an Brase
  • 78,112
  • 7
  • 148
  • 169
  • 1
    But System.arraycopy only copies into an existing array. Arrays.copyOf also creates the output array for you. – Thilo Apr 07 '10 at 03:24
  • 2
    That's true, and so long as you're using System.arraycopy under the covers whatever convenience wrapper you use is just gravy. – Ry4an Brase Apr 07 '10 at 13:28
  • 4
    And, there are cases where `System.arrayCopy` *can't* use a direct memory copy. – Stephen C Nov 22 '11 at 09:29
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.

matsev
  • 32,104
  • 16
  • 121
  • 156
2

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

Nightfirecat
  • 11,432
  • 6
  • 35
  • 51
Humphrey Bogart
  • 7,423
  • 14
  • 52
  • 59
  • 6
    Just because it uses native code via JNI, it does not mean that it will be faster: http://www.javaspecialists.eu/archive/Issue124.html – Dag Nov 27 '12 at 17:26
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

cyberthreat
  • 179
  • 13
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!

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
aran
  • 10,978
  • 5
  • 39
  • 69
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.

Kevin Ng
  • 2,146
  • 1
  • 13
  • 18
-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));
}
 }
Ambika
  • 1