javaarrayscopyclone

Why is clone() the fastest way for copying arrays?


Josh Bloch states in this blog that

You should use clone to copy arrays, because that's generally the fastest way to do it.

I always used System.arraycopy(...). Both approaches are native, so probably without going deeper into the sources of libraries I cannot figure out, why it is so.

Why is it the fastest way?

The difference with System.arraycopy is explained here, but it does not answer the question why Josh Bloch considers clone() as the fastest way.


Solution

  • 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()).