What is more efficient: System.arraycopy or Arrays.copyOf?
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;
}
Why is Arrays.copyOf 2 times faster than System.arraycopy for small arrays?
Your System.arraycopy
benchmark is not semantically equivalent to Arrays.copyOf
.
It will be if you replace
System.arraycopy(ar, 0, result, 0, length);
with
System.arraycopy(ar, 0, result, 0, Math.min(ar.length, length));
With this change, the performance of both benchmarks will also become similar.
Why is the first variant slower then?
Without knowing how
length
relates toar.length
JVM needs to perform additional bounds check and be prepared to throwIndexOutOfBoundsException
whenlength > ar.length
.This also breaks the optimization to eliminate redundant zeroing. You know, every allocated array must be initialized with zeros. However, JIT can avoid zeroing if it sees that the array is filled right after creation. But
-prof perfasm
clearly shows that the originalSystem.arraycopy
benchmark spends a significant amount of time clearing the allocated array:0,84% 0x000000000365d35f: shr $0x3,%rcx
0,06% 0x000000000365d363: add $0xfffffffffffffffe,%rcx
0,69% 0x000000000365d367: xor %rax,%rax
0x000000000365d36a: shl $0x3,%rcx
21,02% 0x000000000365d36e: rep rex.W stos %al,%es:(%rdi) ;*newarray
Manual copy appeared faster for small arrays, because unlike System.arraycopy
it does not perform any runtime calls to VM functions.
Is it better to use System.arraycopy(...) than a for loop for copying arrays?
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!
Why clone() is the best way for copying arrays?
I would like to make some points about why clone()
is the fastest way to copy an array than System.arraycopy(..)
or others:
1. clone()
doesn't have to do the typechecking before copying a source array to the destination one as provided here. It just simple allocates new memory space and assigns the objects to it. On the other hand, System.arraycopy(..)
checks for the type and then copies an array.
2. clone()
also breaks the optimization to eliminate redundant zeroing. As you know, every allocated array in Java must be initialized with 0s
or respective default values. However, JIT can avoid zeroing this array if it sees that the array is filled right after creation. That makes it definitely faster compared to changing the copy values with existing 0s
or respective default values. While using System.arraycopy(..)
spends significant amount of time clearing and copying the initialized array. To do so I have performed some of the benchmark tests.
@BenchmarkMode(Mode.Throughput)
@Fork(1)
@State(Scope.Thread)
@Warmup(iterations = 10, time = 1, batchSize = 1000)
@Measurement(iterations = 10, time = 1, batchSize = 1000)
public class BenchmarkTests {
@Param({"1000","100","10","5", "1"})
private int size;
private int[] original;
@Setup
public void setup() {
original = new int[size];
for (int i = 0; i < size; i++) {
original[i] = i;
}
}
@Benchmark
public int[] SystemArrayCopy() {
final int length = size;
int[] destination = new int[length];
System.arraycopy(original, 0, destination, 0, length);
return destination;
}
@Benchmark
public int[] arrayClone() {
return original.clone();
}
}
Output:
Benchmark (size) Mode Cnt Score Error Units
ArrayCopy.SystemArrayCopy 1 thrpt 10 26324.251 ± 1532.265 ops/s
ArrayCopy.SystemArrayCopy 5 thrpt 10 26435.562 ± 2537.114 ops/s
ArrayCopy.SystemArrayCopy 10 thrpt 10 27262.200 ± 2145.334 ops/s
ArrayCopy.SystemArrayCopy 100 thrpt 10 10524.117 ± 474.325 ops/s
ArrayCopy.SystemArrayCopy 1000 thrpt 10 984.213 ± 121.934 ops/s
ArrayCopy.arrayClone 1 thrpt 10 55832.672 ± 4521.112 ops/s
ArrayCopy.arrayClone 5 thrpt 10 48174.496 ± 2728.928 ops/s
ArrayCopy.arrayClone 10 thrpt 10 46267.482 ± 4641.747 ops/s
ArrayCopy.arrayClone 100 thrpt 10 19837.480 ± 364.156 ops/s
ArrayCopy.arrayClone 1000 thrpt 10 1841.145 ± 110.322 ops/s
According to the outputs I am getting that clone
is almost twice fast from System.arraycopy(..)
3. Also, using manual copying method like clone()
results into faster ouput because it doesn't have to make any VM calls (unlike System.arraycopy()
).
Is Java's System.arraycopy() efficient for small arrays?
Expanding a little on what Sid has written, it's very likely that System.arraycopy
is just a JIT intrinsic; meaning that when code calls System.arraycopy
, it will most probably be calling a JIT-specific implementation (once the JIT tags System.arraycopy
as being "hot") that is not executed through the JNI interface, so it doesn't incur the normal overhead of native methods.
In general, executing native methods does have some overhead (going through the JNI interface, also some internal JVM operations cannot happen when native methods are being executed). But it's not because a method is marked as "native" that you're actually executing it using JNI. The JIT can do some crazy things.
Easiest way to check is, as has been suggested, writing a small benchmark, being careful with the normal caveats of Java microbenchmarks (warm up the code first, avoid code with no side-effects since the JIT just optimizes it as a no-op, etc).
System.arrayCopy is slow
Actually, HotSpot compiler is smart enough to unroll and vectorize manual copy loop - that's why the result code appears to be well optimized.
Why is System.arraycopy
slower then? It is originally a native method, and you have to pay for a native call until the compiler optimizes it as JVM intrinsic.
However, in your test the compiler does not have a chance for such optimization, because enlarge
method is not called many enough times (i.e. it is not considered as hot).
I'll show you a funny trick to force the optimization. Rewrite enlarge
method as follows:
private static int[] enlarge(int[] array, int size) {
for (int i = 0; i < 10000; i++) { /* fool the JIT */ }
int[] newArray = new int[array.length + size];
System.arraycopy(array, 0, newArray, 0, array.length);
return newArray;
}
An empty loop triggers a backedge counter overflow, which in turn triggers the compilation of enlarge
method. The empty loop is then eliminated from the compiled code, so it is harmless. Now enlarge
method gets about 1.5x faster than the manual loop!
It is important that System.arraycopy
immediately follows new int[]
. In this case HotSpot can optimize away the redundant zeroing of newly allocated array. You know, all Java objects must be zeroed right after creation. But as far as compiler detects that the array is filled right after creation, it may eliminate zeroing, thus making the result code yet faster.
P.S. @assylias' benchmark is good, but it also suffers from the fact that System.arraycopy
is not intrinsified for the large arrays. In case of small arrays arrayCopy
benchmark is called many times per second, JIT considers it hot and optimizes well. But for large arrays each iteration is longer, so there is a lot less iterations per second, and JIT does not treat arrayCopy
as hot.
Is there any reason to prefer System.arraycopy() over clone()?
No. If you're really microbenchmarking, then maybe, depending on what JVM you're running. But in actuality, no.
Efficient System.arraycopy on multidimensional arrays
System.arrayCopy
is likely the fastest way to copy an array, but it does not make deep copies.
It also cannot do the more complex example in your second question.
.clone() or Arrays.copyOf()?
Update using jmh
Using jmh, I get similar results, except that clone
seems to be marginally better.
Original post
I ran a quick test for performance: clone
, System.arrayCopy
and Arrays.copyOf
have very similar performance (jdk 1.7.06, server vm).
For details (in ms), after JIT:
clone: 68
arrayCopy: 68
Arrays.copyOf: 68
Test code:
public static void main(String[] args) throws InterruptedException,
IOException {
int sum = 0;
int[] warmup = new int[1];
warmup[0] = 1;
for (int i = 0; i < 15000; i++) { // triggers JIT
sum += copyClone(warmup);
sum += copyArrayCopy(warmup);
sum += copyCopyOf(warmup);
}
int count = 10_000_000;
int[] array = new int[count];
for (int i = 0; i < count; i++) {
array[i] = i;
}
// additional warmup for main
for (int i = 0; i < 10; i++) {
sum += copyArrayCopy(array);
}
System.gc();
// copyClone
long start = System.nanoTime();
for (int i = 0; i < 10; i++) {
sum += copyClone(array);
}
long end = System.nanoTime();
System.out.println("clone: " + (end - start) / 1000000);
System.gc();
// copyArrayCopy
start = System.nanoTime();
for (int i = 0; i < 10; i++) {
sum += copyArrayCopy(array);
}
end = System.nanoTime();
System.out.println("arrayCopy: " + (end - start) / 1000000);
System.gc();
// copyCopyOf
start = System.nanoTime();
for (int i = 0; i < 10; i++) {
sum += copyCopyOf(array);
}
end = System.nanoTime();
System.out.println("Arrays.copyOf: " + (end - start) / 1000000);
// sum
System.out.println(sum);
}
private static int copyClone(int[] array) {
int[] copy = array.clone();
return copy[copy.length - 1];
}
private static int copyArrayCopy(int[] array) {
int[] copy = new int[array.length];
System.arraycopy(array, 0, copy, 0, array.length);
return copy[copy.length - 1];
}
private static int copyCopyOf(int[] array) {
int[] copy = Arrays.copyOf(array, array.length);
return copy[copy.length - 1];
}
Related Topics
Java Spring Boot: How to Map My App Root ("/") to Index.Html
Is There a Fixed Sized Queue Which Removes Excessive Elements
Is There an Upper Bound to Biginteger
How to Sum Digits of an Integer in Java
Java:Non-Static Variable Cannot Be Referenced from a Static Context Error
Creating a "Logical Exclusive Or" Operator in Java
Calling Outer Class Function from Inner Class
How to Move a File from One Location to Another in Java
Difference Between List, List<>, List<T>, List<E>, and List<Object>
How to Find the Sum of All the Numbers in an Array in Java
How to Remove a Cookie in a Java Servlet
Unit Testing a Class with a Java 8 Clock
How to Keep a Scanner from Throwing Exceptions When the Wrong Type Is Entered
Applying Map of the Earth Texture a Sphere
Embedded Mongodb When Running Integration Tests
Best Way to Make Java's Modulus Behave Like It Should with Negative Numbers