Java Forum / General / March 2007
System.arrayCopy Vs array clone
mei - 27 Feb 2007 20:52 GMT Hello,
I read in bloch's effective java that the only interesting use of clone() is to copy array cheaply. On the web, I found opposite opinions: Some people pretend that instantiate a new array, then call System.arrayCopy is faster. I made a quick bench that seems to confirm this second hypothesis. However, with all the respect I have for the author, I wished all the same to ask the question on this newsgroup. Is there something I and a few other people from the Internet missed? Thanks in advance, Mei.
Daniel Pitts - 27 Feb 2007 21:22 GMT > Hello, > [quoted text clipped - 8 lines] > Thanks in advance, > Mei. Its probably an "out of date" assertion. True when written, but false now. You have to remember that Java has gone through a lot of optimizations through the years. Its quite possible that "new int[100]" and System.arrayCopy() have been optimized, and array.clone() has not.
You may noticed that in Java 1.6, there is a new way to "copy" arrays. <http://java.sun.com/javase/6/docs/api/java/util/ Arrays.html#copyOf(T[],%20int)>, making clone obsolete, and limiting the need for explicit arrayCopy calls.
Lew - 28 Feb 2007 04:07 GMT >> Hello, >> [quoted text clipped - 10 lines] > > Its probably an "out of date" assertion. No, it remains interesting. Notice that Bloch doesn't say "recommended" use.
There have been a number of threads here touching on the dangers of assuming performance characteristics in a Java program, especially between versions. Algorithmic characteristics of a benchmark and execution profiles from its testbed both influence the outcome.
Since you actually measured the performance you have some facts about System.arrayCopy(). Would you be willing to share your benchmark code and how you ran it?
- Lew
mei - 28 Feb 2007 18:50 GMT Hello Lew,
Lew a écrit :
> No, it remains interesting. Notice that Bloch doesn't say "recommended" > use. I don't understand. What do you mean?
> [...] > > Since you actually measured the performance you have some facts about > System.arrayCopy(). Would you be willing to share your benchmark code > and how you ran it? Hereunder is the benchmark code I wrote. Since I am not a specialist for writing such kind of code, if you detect any flaws, please let me know. I used java hotspot 1.5.0_10
public class Bench { private static final int[] tableau = {1, 2, 3, 4, 5, 6, 7, 8, 9}; private static final int count = 1000000;
static void testCopy() { long startTime = System.currentTimeMillis(); long res = 0; for (int i = 0; i < count; i++) { int[] copy = new int[tableau.length]; System.arraycopy(tableau, 0, copy, 0, tableau.length); for (int j = 0; j < copy.length; j++) res += copy[j]; } long endTime = System.currentTimeMillis(); System.out.println("testCopy(): dummy result=" + res + " time=" + (endTime - startTime)); }
static void testClone() { long startTime = System.currentTimeMillis(); long res = 0; for (int i = 0; i < count; i++) { int[] copy = tableau.clone(); for (int j = 0; j < copy.length; j++) res += copy[j]; } long endTime = System.currentTimeMillis(); System.out.println("testClone(): dummy result=" + res + " time=" + (endTime - startTime)); }
public static void main(String[] args) { testCopy(); testClone();
testCopy(); testClone();
testCopy(); testClone(); } }
Here's a typical output:
testCopy(): dummy result=45000000 time=140 testClone(): dummy result=45000000 time=438 testCopy(): dummy result=45000000 time=125 testClone(): dummy result=45000000 time=437 testCopy(): dummy result=45000000 time=125 testClone(): dummy result=45000000 time=454
Arne Vajhøj - 28 Feb 2007 03:41 GMT > I read in bloch's effective java that the only interesting use of > clone() is to copy array cheaply. On the web, I found opposite opinions: [quoted text clipped - 4 lines] > same to ask the question on this newsgroup. Is there something I and a > few other people from the Internet missed? It probably depend on Java vendor, platform and version.
Meaning that there are a few hundred possible results.
There are absolutely no guarantee that IBM Java 1.3.1 on AIX PPC will have same characteristics as SUN Java 1.5.0 on Win32 x86.
That said then my expectation will be that: - the difference is small because they basically do the same thing - extremely few real world applications will be effected by the difference
Arne
mei - 28 Feb 2007 18:58 GMT Hello Arne,
Arne Vajhøj a écrit :
> It probably depend on Java vendor, platform and version. > > Meaning that there are a few hundred possible results. > > There are absolutely no guarantee that IBM Java 1.3.1 on AIX PPC > will have same characteristics as SUN Java 1.5.0 on Win32 x86. True. I'm using Java 1.5 and win32 x86. J. Bloch were using Java 1.3 and win32 x86. However he didn't say explicitly that he ran such benchmark by himself for this matter. His expression was: "Because of its many shortcomings, some expert programmers simply choose never to override the clone method and never to invoke it except, perhaps, to copy arrays cheaply".
> That said then my expectation will be that: > - the difference is small because they basically do the same thing Hmmm... Clone() entails the navigation through the inheritance hierarchy to finally invoke Object.clone(), then by a mechanism I ignore the details provide an instance of the correct type.
> - extremely few real world applications will be effected by the > difference > > Arne Lew - 01 Mar 2007 06:03 GMT > Hmmm... Clone() entails the navigation through the inheritance hierarchy > to finally invoke Object.clone(), then by a mechanism I ignore the > details provide an instance of the correct type. That doesn't happen at run time. The class that inherits Object has a direct dispatch to its own inherited methods; it doesn't need to do some sort of hierarchical search at runtime for a class that implements the method.
-- Lew
mei - 01 Mar 2007 18:55 GMT Lew a écrit :
> That doesn't happen at run time. The class that inherits Object has a > direct dispatch to its own inherited methods; it doesn't need to do some > sort of hierarchical search at runtime for a class that implements the > method. Ok. Thank you.
Eric Sosman - 01 Mar 2007 15:57 GMT Arne Vajhøj wrote On 02/27/07 22:41,:
>>I read in bloch's effective java that the only interesting use of >>clone() is to copy array cheaply. On the web, I found opposite opinions: [quoted text clipped - 14 lines] > That said then my expectation will be that: > - the difference is small because they basically do the same thing My expectations were a lot like yours, but I ran some timing tests and was surprised. On my vendor/platform/version combination, duplicating an int[N] array takes
0.035*N + 2.44 microseconds for clone() 0.020*N + 0.38 microseconds for new + arrayCopy 0.045*N - 0.28 microseconds for new + for-loop
(These are straight-line regressions for values of N in {0,1,10,100,1000,2500,5000,7500,10000}, with the number of repetitions at each N adjusted to make the test take roughly four seconds. The sign of the constant term in the third method suggests that copying lots and lots of zero-length arrays with new-plus-loop could make your program arbitrarily fast, but I wouldn't place a whole lot of faith in that conclusion ...)
On my configuration, then, new-plus-arrayCopy is the fastest, cloning takes 75% longer, and new-plus-loop takes 125% longer.
> - extremely few real world applications will be effected by the > difference Agreed; these timing tests have little practical use.
 Signature Eric.Sosman@sun.com
Arne Vajhøj - 02 Mar 2007 03:26 GMT > Arne Vajhøj wrote On 02/27/07 22:41,: >>> I read in bloch's effective java that the only interesting use of [quoted text clipped - 36 lines] > fastest, cloning takes 75% longer, and new-plus-loop takes > 125% longer. I tried with a test also.
Results are below.
They seem rather blurred to me.
Arne
================================================
C:\>type CloneSpeed.java public class CloneSpeed { private final static int N = 10000; private final static int REP = 100000; public static void main(String[] args) { int[] a = new int[N]; long t1 = System.currentTimeMillis(); for(int i = 0; i < REP; i++) { int[] b = (int[])a.clone(); } long t2 = System.currentTimeMillis(); System.out.println("clone: " + (t2-t1)); long t3 = System.currentTimeMillis(); for(int i = 0; i < REP; i++) { int[] b = new int[a.length]; System.arraycopy(a, 0, b, 0, a.length); } long t4 = System.currentTimeMillis(); System.out.println("arraycopy: " + (t4-t3)); } }
C:\>java -version java version "1.5.0" Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-b64) Java HotSpot(TM) Client VM (build 1.5.0-b64, mixed mode)
C:\>javac CloneSpeed.java
C:\>java CloneSpeed clone: 2641 arraycopy: 2453
C:\>java CloneSpeed clone: 2969 arraycopy: 2453
C:\>java CloneSpeed clone: 2609 arraycopy: 2469
C:\>java -server CloneSpeed clone: 3282 arraycopy: 3140
C:\>java -server CloneSpeed clone: 3297 arraycopy: 3140
C:\>java -server CloneSpeed clone: 3281 arraycopy: 3141
C:\>java -version java version "1.6.0" Java(TM) SE Runtime Environment (build 1.6.0-b105) Java HotSpot(TM) Client VM (build 1.6.0-b105, mixed mode, sharing)
C:\>javac CloneSpeed.java
C:\>java CloneSpeed clone: 2844 arraycopy: 3016
C:\>java CloneSpeed clone: 2843 arraycopy: 3000
C:\>java CloneSpeed clone: 2875 arraycopy: 3031
C:\>java -server CloneSpeed clone: 3281 arraycopy: 3140
C:\>java -server CloneSpeed clone: 3312 arraycopy: 3328
C:\>java -server CloneSpeed clone: 3265 arraycopy: 3188
Lew - 03 Mar 2007 14:20 GMT > C:\>type CloneSpeed.java > public class CloneSpeed { [quoted text clipped - 17 lines] > } > } For tests like this, would it make sense to run the loop a bunch of times before measuring the speed in order to let the Hotspot mechanism settle down?
-- Lew
Chris Uppal - 03 Mar 2007 20:38 GMT > For tests like this, would it make sense to run the loop a bunch of times > before measuring the speed in order to let the Hotspot mechanism settle > down? It normally would be /much/ better, but in this specific case I don't think it makes a lot of difference. One reason is that each loop of the test is quite long (longer than I would normally use myself); the other is that both clone() and arrayCopy() end up in precompiled (not JITed) code for the bulk of their execution time, so there's not much for the JITer to do. It would probably have made a more significant difference if we were including hand-written loop in the benchmark (as in "mie"'s code).
Still, and for what it's worth, I wrapped a loop around the test. Code follow at the end.
With SIZE = 10,000 and LOOPS = 100,000, I didn't find a lot of difference beween copy() and new()+arrayCopy() using a 1.5 or 1.6, client or server, JVM (there were small differences but not enough to be worth discussing). On the other hand, with a much smaller array, such as "mei" used, SIZE = 10 and LOOPS = 10,000,000, there were very considerable differences, with clone() typically about 3 or 4 times slower (depending on which JVM I used). But then, the time taken to copy a small array is much less likely to have a significant effect on the overal runtime of a program.
I suspect there may be a test somewhere in the implementation of clone() which switches to a faster implementation for arrays over a certain size.
Incidentally, one consistent feature of the numbers is that the 1.5 JVM was a bit faster than the 1.6 for this benchmark...
-- chris
================================ public class Test { private final static int SIZE = 10 * 1000; private final static int LOOPS = 100 * 1000; public static void main(String[] args) { System.out.println("Clone()\t\tNew()+ArrayCopy()"); int[] a = new int[SIZE]; for (;;) timeIt(a); }
private static void timeIt(int[] a) { long start = System.currentTimeMillis(); for(int i = 0; i < LOOPS; i++) { int[] b = (int[])a.clone(); } long end = System.currentTimeMillis(); System.out.print((end-start) + "\t\t");
start = System.currentTimeMillis(); for(int i = 0; i < LOOPS; i++) { int[] b = new int[a.length]; System.arraycopy(a, 0, b, 0, a.length); } end = System.currentTimeMillis(); System.out.println((end-start)); } } ================================
Arne Vajhøj - 04 Mar 2007 03:00 GMT > With SIZE = 10,000 and LOOPS = 100,000, I didn't find a lot of difference > beween copy() and new()+arrayCopy() using a 1.5 or 1.6, client or server, JVM [quoted text clipped - 4 lines] > taken to copy a small array is much less likely to have a significant effect on > the overal runtime of a program. A completeley non scientific explanation build on gut feeling is that clone has more runtime overhead to verify that the object is cloneable and that the assignment should not give a class cast exception than arraycopy use to verify that src and dst are the same type.
> Incidentally, one consistent feature of the numbers is that the 1.5 JVM was a > bit faster than the 1.6 for this benchmark... A new version can not fe faster at everything. I belive that 1.6 in general are sligtly faster than 1.5.
Arne
Arne Vajhøj - 04 Mar 2007 02:52 GMT >> C:\>type CloneSpeed.java >> public class CloneSpeed { [quoted text clipped - 21 lines] > times before measuring the speed in order to let the Hotspot mechanism > settle down? Maybe.
But if the non-optimized number of iterations is significant in 100000 repetitions, then I would say that the non-optimized results are probably more relevant than the optimized one.
Arne
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|