.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];
}
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()
).
clone() method in ArrayList, why Arrays.copyOf()?
No it doesn't, the first method creates a copy of the underlying array (attention: it's a copy of the array - not the objects in the array!).
The latter creates an ArrayList that points to the same array as the original object.
Example:
String[][] s1 = {{new String("a"), new String("b")}};
String[][] s2 = s1.clone();
System.out.println(Arrays.toString(s1)); // prints [[Ljava.lang.String;@7440e464]
System.out.println(Arrays.toString(s2)); // prints [[Ljava.lang.String;@7440e464]
System.out.println(s1[0] == s2[0]); // prints true
System.out.println(s1 == s2); // prints false - because s2 != s1
Since the array of arrays is an object, and the item in the first place (s[0]
) is an array itself (which is an object as well) - you can see that clone simply copied the reference to the objects.
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;
}
Does Arrays.copyOf produce a shallow or a deep copy?
It produces a shallow copy, i.e. a new array that contains "old" references (to the same objects, those are not being copied).
In particular, if you have nested arrays, those will not be copied. You will just get a new array whose "top level" points to the same "second level" arrays as the original did. Any changes inside those nested arrays will be reflected in both copy and original.
This test suggests that the copy is deep:
No, it does not. When you assign a new object to the "original" array, this does not affect the copy. It is, after all, a copy.
This is the same situation as:
String x = "foo";
String y = x;
x = "bar";
assertEquals(y, "foo");
No "deep copy" here.
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.
Related Topics
Spring MVC: How to Return Custom 404 Errorpages
Why Are New Java.Util.Arrays Methods in Java 8 Not Overloaded for All the Primitive Types
How to Find Out If "Debug Mode" Is Enabled
Jaxb Creating Context and Marshallers Cost
Auto Adjust the Height of Rows in a Jtable
Check If Int Is Between Two Numbers
Should I Retrieve Database Record in Struts2 View Layer
Printing a JPAnel with Scrollable Jtable on It
Using Bufferedreader.Readline() in a While Loop Properly
Getting Enum Associated with Int Value
Allowing the "Enter" Key to Press the Submit Button, as Opposed to Only Using Mouseclick
How to Use 3Rd Party Library in Java9 Module
Can an Interface Extend Multiple Interfaces in Java
Java JSON Serialization - Best Practice
Jcomponent Stops Getting Rendered Once It Goes Off the Screen