Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6912521

System.arraycopy works slower than the simple loop for little lengths

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Fixed
    • Icon: P5 P5
    • 9
    • tbd
    • hotspot
    • b55
    • x86
    • windows_vista

        A DESCRIPTION OF THE REQUEST :
        When we copy one Java array to another, there are two possible ways: System.arraycopy method and the simple loop like this:
            for (int j = 0; j < a.length; j++)
                b[j] = a[j];
        All Java tutorials recommend using System.arraycopy, when possible: it works faster and is written more shortly. Moreover, some professional IDEs, like IntelliJ IDEA, detect simple loops, like the loop above, and warn about a nonoptimal code.

        However, for very short array (a.length=1,2,3), the testing shows that the simple loop works essentially faster then System.arraycopy. Below is a simple test illustrating this:

        import java.util.Locale;

        public class ArraycopySpeed {
            public static void main(String[] args) {
                if (args.length < 3) {
                    System.out.println("Usage: " + ArraycopySpeed.class.getName()
                        + " maxArrayLength loopLength numberOfIterations");
                    return;
                }
                final int maxLen = Integer.parseInt(args[0]);
                final int n = Integer.parseInt(args[1]);
                int numberOfIterations = Integer.parseInt(args[2]);
                for (int iter = 1; iter <= numberOfIterations; iter++) {
                    System.out.println("Test #" + iter);
                    for (int len = 0; len < maxLen; len++) {
                        int[] a = new int[len], b = new int[len];
                        long t1 = System.nanoTime();
                        for (int k = 0; k < n; k++) {
                            for (int j = 0; j < a.length; j++)
                                b[j] = a[j];
                        }
                        long t2 = System.nanoTime();
                        for (int k = 0; k < n; k++) {
                            System.arraycopy(a, 0, b, 0, a.length);
                        }
                        long t3 = System.nanoTime();
                        System.out.printf(Locale.US, "%d elements: %.3f ns simple loop, %.3f ns arraycopy %n",
                            len, (double)(t2 - t1) / n, (double)(t3 - t2) / n);
                    }
                    System.out.println();
                }
            }
        }

        On my computer (Intel Quad Core, Windows Vista-64, JVM 1.7.0-ea-b74, 64 bit) only for 5 or more elements System.arraycopy becomes the optimal solution. For Is it possible to improve this behavior and always translate short arraycopy calls into an optimal code?


        JUSTIFICATION :
        If we need to copy short Java arrays in inner loops and this code is critical for the application performance, we are enforced to create an ugly code like the following:
        if (a.length < 5) {
            for (int j = 0; j < a.length; j++)
                b[j] = a[j];
        } else {
            System.arraycopy(a, 0, b, 0, a.length);
        }
        and there are no any guarantees that it will be the right choice for any JVMs. It can be really important, for example, if a Java array contains 2 or 3 coordinates in a plane or 3D space, and the algorithm copies one set of coordinates to another while processing millions of points. In my last module the Java array was used for storing a set of indexes in some multilevel histogram, and the number of indexes varies from 1 to 5-6.

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        System.arraycopy should always work faster than an equivalent Java loop.
        ACTUAL -
        For short arrays (several elements) Java loop sometimes works faster than System.arraycopy.

        ---------- BEGIN SOURCE ----------
        import java.util.Locale;

        public class ArraycopySpeed {
            public static void main(String[] args) {
                if (args.length < 3) {
                    System.out.println("Usage: " + ArraycopySpeed.class.getName()
                        + " maxArrayLength loopLength numberOfIterations");
                    return;
                }
                final int maxLen = Integer.parseInt(args[0]);
                final int n = Integer.parseInt(args[1]);
                int numberOfIterations = Integer.parseInt(args[2]);
                for (int iter = 1; iter <= numberOfIterations; iter++) {
                    System.out.println("Test #" + iter);
                    for (int len = 0; len < maxLen; len++) {
                        int[] a = new int[len], b = new int[len];
                        long t1 = System.nanoTime();
                        for (int k = 0; k < n; k++) {
                            for (int j = 0; j < a.length; j++)
                                b[j] = a[j];
                        }
                        long t2 = System.nanoTime();
                        for (int k = 0; k < n; k++) {
                            System.arraycopy(a, 0, b, 0, a.length);
                        }
                        long t3 = System.nanoTime();
                        System.out.printf(Locale.US, "%d elements: %.3f ns simple loop, %.3f ns arraycopy %n",
                            len, (double)(t2 - t1) / n, (double)(t3 - t2) / n);
                    }
                    System.out.println();
                }
            }
        }

        ---------- END SOURCE ----------

        CUSTOMER SUBMITTED WORKAROUND :
        Manual choosing between System.arraycopy and simple Java loop for a case of short arrays.

              roland Roland Westrelin
              ndcosta Nelson Dcosta (Inactive)
              Votes:
              0 Vote for this issue
              Watchers:
              3 Start watching this issue

                Created:
                Updated:
                Resolved:
                Imported:
                Indexed: