-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Xie,

On 3/3/2010 11:54 AM, Xie Xiaodong wrote:
> I think log.debug() method should first check current logging levels, or our
> code will have those if() {} template everywhere.

[snip]

> For log.debug() part, seems I misunderstood your meaning. Sorry about that,
> you are right. But I do not think it matters too much. :)

Well, if were using tricks to avoid synchronization, we probably ought
to avoid four object creations (StringBuilder, char[] in sb, String, and
char[] in s) plus the character-copy operations. This is a filter that
is supposed to avoid performance impact on the webapp: this is such a
cheap optimization, it would be foolish not to do it.

> Java 6 hotspot can determine that the StringBuffer synchronization isn't
> actually used across threads in many cases, and thus it doesn't bother
> synchronizing. Thus, the performance of the two classes becomes identical.
> 
> http://www.javalobby.org/java/forums/t88518.html

It's a rough reference from a comment on a blog. Gimmie something I can
really read, not "I remember a guy saying once..".

Jeremy Manson says this:
"
A final note. Some people think that there is no performance impact to
using StringBuffer instead of StringBuilder, because of all of the
clever things JVMs do to eliminate synchronization (I can blog about
this, too, if you want). This is a little unclear. Whether it can even
perform these optimizing transformations definitely depends wildly on
which JDK you use; I wrote a microbenchmark to test it, and the results
differed on different JDKs -- but all that microbenchmarks really
demonstrate is the performance of the microbenchmark.
"
(http://jeremymanson.blogspot.com/2008/08/dont-use-stringbuffer.html
from 24 August 2008)

> But it is more secure to not depend on specific jvm version, so it is more
> appropriate to use StringBuilder when necessary.

I agree. Using my own microbenchmark (below), these are the results I get:

(On my OpenVZ dev box, Linux 2.6 kernel)
$ java -showversion BufferVsBuilder 10000000
java version "1.6.0_12"
Java(TM) SE Runtime Environment (build 1.6.0_12-b04)
Java HotSpot(TM) Server VM (build 11.2-b01, mixed mode)

Priming...
Running...............
Builder:   24538
Buffer:    25745
Overhead:  1657

$ java -showversion BufferVsBuilder 10000000
java version "1.6.0_12"
Java(TM) SE Runtime Environment (build 1.6.0_12-b04)
Java HotSpot(TM) Server VM (build 11.2-b01, mixed mode)

Priming...
Running...............
Builder:   24175
Buffer:    25416
Overhead:  1656


(On my laptop, W7 32-bit)
F:\Users\Chris\Desktop>java -showversion BufferVsBuilder 10000000
java version "1.6.0_18"
Java(TM) SE Runtime Environment (build 1.6.0_18-b07)
Java HotSpot(TM) Client VM (build 16.0-b13, mixed mode, sharing)

Priming...
Running...............
Builder:   27507
Buffer:    31525
Overhead:  1183

F:\Users\Chris\Desktop>java -showversion BufferVsBuilder 10000000
java version "1.6.0_18"
Java(TM) SE Runtime Environment (build 1.6.0_18-b07)
Java HotSpot(TM) Client VM (build 16.0-b13, mixed mode, sharing)

Priming...
Running...............
Builder:   27339
Buffer:    31346
Overhead:  1116

It seems that, in these two environments, StringBuilder outperforms
StringBuffer by a small margin (5% on average in my Linux environment,
13% in my Microsoft Windows environment), but consistently.

It seems that the JVM has to do some work to even determine if the
synchronization can be eliminated before it can actually do it, so why
bother making it do that work in the first place? Avoiding
synchronization is simply the right choice.

- -chris

The code:
public class BufferVsBuilder
{
    static long elapsedBuilder = 0;
    static long elapsedBuffer = 0;
    static long elapsedNothing = 0;

    public static void testBuilder(long iterations)
    {
        long elapsed = System.currentTimeMillis();

        for(long i=iterations; i>0; --i)
        {
            StringBuilder sb = new StringBuilder(128);
            sb.append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                ;
        }

        elapsed = System.currentTimeMillis() - elapsed;

        elapsedBuilder += elapsed;
    }

    public static void testBuffer(long iterations)
    {
        long elapsed = System.currentTimeMillis();

        for(long i=iterations; i>0; --i)
        {
            StringBuffer sb = new StringBuffer(128);
            sb.append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                .append("some text")
                ;
        }

        elapsed = System.currentTimeMillis() - elapsed;

        elapsedBuffer += elapsed;
    }

    public static void testNothing(long iterations)
    {
        long elapsed = System.currentTimeMillis();

        for(long i=iterations; i>0; --i)
        {
            StringBuffer sb = new StringBuffer(128);
        }

        elapsed = System.currentTimeMillis() - elapsed;

        elapsedNothing += elapsed;
    }


    public static void main(String[] args)
    {
        long iterations = Long.parseLong(args[0]);

        System.out.println("Priming..."); System.out.flush();
        // Allow the JIT to work it's magic
        testBuilder(iterations);
        testBuffer(iterations);

        // Re-set counters and start the real tests
        elapsedBuilder = 0;
        elapsedBuffer = 0;

        System.out.print("Running..."); System.out.flush();
        testBuilder(iterations);
        System.out.print("."); System.out.flush();
        testBuffer(iterations);

        System.out.print("."); System.out.flush();
        testBuilder(iterations);
        System.out.print("."); System.out.flush();
        testBuffer(iterations);

        System.out.print("."); System.out.flush();
        testBuilder(iterations);
        System.out.print("."); System.out.flush();
        testBuffer(iterations);

        System.out.print("."); System.out.flush();
        testBuilder(iterations);
        System.out.print("."); System.out.flush();
        testBuffer(iterations);

        System.out.print("."); System.out.flush();
        testBuilder(iterations);
        System.out.print("."); System.out.flush();
        testBuffer(iterations);

        System.out.print("."); System.out.flush();
        testBuilder(iterations);
        System.out.print("."); System.out.flush();
        testBuffer(iterations);

        System.out.print("."); System.out.flush();
        testNothing(iterations);

        System.out.println();
        System.out.println("Builder:   " + elapsedBuilder);
        System.out.println("Buffer:    " + elapsedBuffer);
        System.out.println("Overhead:  " + elapsedNothing);
    }
}
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iEYEARECAAYFAkuOrj0ACgkQ9CaO5/Lv0PCAbgCeLkbndgo1VsC/M+e2dGfVy3Fl
4dMAoKCHnBRwZvayRdSPXibVxFI7Hes3
=k26e
-----END PGP SIGNATURE-----

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org
For additional commands, e-mail: users-h...@tomcat.apache.org

Reply via email to