[PATCH] Performance bug in String(byte[],int,int,Charset)

Martin Buchholz Martin.Buchholz at Sun.COM
Wed Jan 9 06:01:11 UTC 2008


The slowness of array.clone() has been fixed as of jdk6 and 5.0u6.

6428387: array clone() much slower than Arrays.copyOf
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6428387

The rest of this message is the latest version of my private
microbenchmark to measure the fix:

import java.util.*;

public class ArrayCopyMicroBenchmark {
    abstract static class Job {
	private final String name;
	Job(String name) { this.name = name; }
	String name() { return name; }
	abstract void work() throws Throwable;
    }

    private static void collectAllGarbage() {
	try {
	    for (int i = 0; i < 2; i++) {
		System.gc(); System.runFinalization(); Thread.sleep(10);
	    }
	} catch (InterruptedException e) { throw new Error(e); }
    }

    /**
     * Runs each job for long enough that all the runtime compilers
     * have had plenty of time to warm up, i.e. get around to
     * compiling everything worth compiling.
     * Returns array of average times per job per run.
     */
    private static long[] time0(Job ... jobs) throws Throwable {
	final long warmupNanos = 10L * 1000L * 1000L * 1000L;
	long[] nanoss = new long[jobs.length];
	for (int i = 0; i < jobs.length; i++) {
	    collectAllGarbage();
	    long t0 = System.nanoTime();
	    long t;
	    int j = 0;
	    do { jobs[i].work(); j++; }
	    while ((t = System.nanoTime() - t0) < warmupNanos);
	    nanoss[i] = t/j;
	}
	return nanoss;
    }

    private static void time(Job ... jobs) throws Throwable {

	long[] warmup = time0(jobs); // Warm up run
	long[] nanoss = time0(jobs); // Real timing run

	final String nameHeader = "Method";
	int nameWidth = nameHeader.length();
	for (Job job : jobs)
	    nameWidth = Math.max(nameWidth, job.name().length());

	final String millisHeader = "Millis";
	int millisWidth = millisHeader.length();
	for (long nanos : nanoss)
	    millisWidth =
		Math.max(millisWidth,
			 String.format("%d", nanos/(1000L * 1000L)).length());

	final String ratioHeader = "Ratio";
	int ratioWidth = ratioHeader.length();

	String format = String.format("%%-%ds %%%dd %%.3f%%n",
				      nameWidth, millisWidth);
	String headerFormat = String.format("%%-%ds %%-%ds %%-%ds%%n",
					    nameWidth, millisWidth, ratioWidth);
	System.out.printf(headerFormat, "Method", "Millis", "Ratio");

	// Print out absolute and relative times, calibrated against first job
	for (int i = 0; i < jobs.length; i++) {
	    long millis = nanoss[i]/(1000L * 1000L);
	    double ratio = (double)nanoss[i] / (double)nanoss[0];
	    System.out.printf(format, jobs[i].name(), millis, ratio);
	}
    }

    private static int intArg(String[] args, int i, int defaultValue) {
	return args.length > i ? Integer.parseInt(args[i]) : defaultValue;
    }

    private static void deoptimize(Object[] a) {
	for (Object x : a)
	    if (x == null)
		throw new Error();
    }

    public static void main(String[] args) throws Throwable {
	final int iterations = intArg(args, 0, 100000);
	final int size       = intArg(args, 1, 1000);
	final Object[] array = new Object[size];
	final Random rnd = new Random();
	for (int i = 0; i < array.length; i++)
	    array[i] = rnd.nextInt(size);

	time(
	    new Job("arraycopy") { void work() {
		Object[] a = array;
		for (int i = 0; i < iterations; i++) {
		    Object[] t = new Object[size];
		    System.arraycopy(a, 0, t, 0, size);
		    a = t;}
		deoptimize(a);}},
	    new Job("copyOf") { void work() {
		Object[] a = array;
		for (int i = 0; i < iterations; i++)
		    a = Arrays.copyOf(a, size);
		deoptimize(a);}},
	    new Job("clone") { void work() {
		Object[] a = array;
		for (int i = 0; i < iterations; i++)
		    a = a.clone();
		deoptimize(a);}},
	    new Job("loop") { void work() {
		Object[] a = array;
		for (int i = 0; i < iterations; i++) {
		    Object[] t = new Object[size];
		    for (int j = 0; j < size; j++)
			t[j] = a[j];
		    a = t;}
		deoptimize(a);}}
	    );
    }
}

Clemens Eisserer wrote:
> Hello again,
> 
>>By the way, using clone() seams better than Arrays.copyOf() here.
>>
>>byte[] b = ba.clone();
> 
> Why? I remember that I've seen some benchmarks where array.clone() was
> way slower than creating a new array and using System.arraycopy()
> (which is exactly what copyOf does). However this may have changed ;)
> 
> lg Clemens



More information about the core-libs-dev mailing list