StringBuilder's performance lower than that of StringBuffer

Discussion in 'Java' started by Raga, Aug 24, 2006.

  1. Raga

    Raga Guest

    Hi,

    I read in many websites than StringBuilder offers better performance
    than StringBuffer. So, in my code, I changed all StringBuffer usages to
    StringBuilder. But now the performance has worsened. Is it that
    StringBuffer is really more performant? Also, is there any better
    performant way than using StringBuilder & StringBuffer?

    Thanks.
     
    Raga, Aug 24, 2006
    #1
    1. Advertising

  2. Raga wrote:

    > I read in many websites than StringBuilder offers better performance
    > than StringBuffer. So, in my code, I changed all StringBuffer usages to
    > StringBuilder. But now the performance has worsened. Is it that
    > StringBuffer is really more performant? Also, is there any better
    > performant way than using StringBuilder & StringBuffer?


    By "performant," I think you mean "performing." :)

    StringBuffer is supposed to be thread-safe. Since StringBuilder offers
    no such guarantee, it is potentially much faster. I don't think we're
    talking about a difference in big-O complexity, though, just a constant
    factor speed difference.


    Hmmm... A quick test makes this it look an awful lot like StringBuilder
    has *more* overhead, but is using a better algorithm. Odd. The code is
    below: For 1024 iterations, I got the same result you did, i.e.
    StringBuffer gave better performance:

    StringBuffer: 1268318 ns
    StringBuilder: 1804978 ns

    For 1024*1024 iterations, though, the reverse was the case:

    StringBuffer: 170694041 ns
    StringBuilder: 127406416 ns

    I reiterate: Hmmm...

    public class Main {

    static final int numIterations = 1024 * 1024;

    public static void main(String[] args){

    StringBuffer sbuf =
    new StringBuffer("same text as the other guy");
    StringBuilder sbld =
    new StringBuilder("same text as the other guy");

    long t = System.nanoTime();

    for(int i = 0; i < numIterations; ++i) {
    sbuf.append("a");
    sbuf.deleteCharAt(0);
    }

    t = System.nanoTime() - t;
    System.out.println("StringBuffer:\t" + t + " ns");

    t = System.nanoTime();

    for(int i = 0; i < numIterations; ++i) {
    sbld.append("a");
    sbld.deleteCharAt(0);
    }

    t = System.nanoTime() - t;
    System.out.println("StringBuilder:\t" + t + " ns");
    }
    }
     
    Jeffrey Schwab, Aug 24, 2006
    #2
    1. Advertising

  3. Jeffrey Schwab wrote:
    > Raga wrote:
    >
    >> I read in many websites than StringBuilder offers better performance
    >> than StringBuffer. So, in my code, I changed all StringBuffer usages to
    >> StringBuilder. But now the performance has worsened. Is it that
    >> StringBuffer is really more performant? Also, is there any better
    >> performant way than using StringBuilder & StringBuffer?

    >
    > By "performant," I think you mean "performing." :)
    >
    > StringBuffer is supposed to be thread-safe. Since StringBuilder offers
    > no such guarantee, it is potentially much faster. I don't think we're
    > talking about a difference in big-O complexity, though, just a constant
    > factor speed difference.
    >
    >
    > Hmmm... A quick test makes this it look an awful lot like StringBuilder
    > has *more* overhead, but is using a better algorithm. Odd. The code is
    > below: For 1024 iterations, I got the same result you did, i.e.
    > StringBuffer gave better performance:


    The actual performance is going to be very dependent on the operation
    mix. A variation of your program suggests that some of the effects may
    be due to outside influences such as page faulting or cache missing. I
    modified the program to do each test multiple times, alternating:

    StringBuffer: 3255575 ns
    StringBuilder: 6224512 ns
    StringBuffer: 3741265 ns
    StringBuilder: 2922576 ns
    StringBuffer: 296705 ns
    StringBuilder: 229733 ns
    StringBuffer: 186285 ns
    StringBuilder: 148315 ns
    StringBuffer: 1421934 ns
    StringBuilder: 149066 ns
    StringBuffer: 181475 ns
    StringBuilder: 145825 ns
    StringBuffer: 192282 ns
    StringBuilder: 143341 ns
    StringBuffer: 185336 ns
    StringBuilder: 151989 ns

    The first two lines look as though StringBuffer is faster than
    StringBuilder, but the later lines suggest the opposite. I assume this
    behavior is unrelated to the real program issue.

    Here's my version of the program:

    public class StringBufferPerformance {

    static final int numIterations = 1024;

    public static void main(String[] args){

    StringBuffer sbuf =
    new StringBuffer("same text as the other guy");
    StringBuilder sbld =
    new StringBuilder("same text as the other guy");

    timeBuffer(sbuf);
    timeBuilder(sbld);
    timeBuffer(sbuf);
    timeBuilder(sbld);
    timeBuffer(sbuf);
    timeBuilder(sbld);
    timeBuffer(sbuf);
    timeBuilder(sbld);
    timeBuffer(sbuf);
    timeBuilder(sbld);
    timeBuffer(sbuf);
    timeBuilder(sbld);
    timeBuffer(sbuf);
    timeBuilder(sbld);
    timeBuffer(sbuf);
    timeBuilder(sbld);
    }

    /**
    * @param sbld
    */
    private static void timeBuilder(StringBuilder sbld) {
    long t;
    t = System.nanoTime();

    for(int i = 0; i < numIterations; ++i) {
    sbld.append("a");
    sbld.deleteCharAt(0);
    }

    t = System.nanoTime() - t;
    System.out.println("StringBuilder:\t" + t + " ns");
    }

    /**
    * @param sbuf
    */
    private static void timeBuffer(StringBuffer sbuf) {
    long t = System.nanoTime();

    for(int i = 0; i < numIterations; ++i) {
    sbuf.append("a");
    sbuf.deleteCharAt(0);
    }

    t = System.nanoTime() - t;
    System.out.println("StringBuffer:\t" + t + " ns");
    }
    }
     
    Patricia Shanahan, Aug 24, 2006
    #3
  4. Patricia Shanahan wrote:
    > Jeffrey Schwab wrote:
    >> Raga wrote:
    >>
    >>> I read in many websites than StringBuilder offers better performance
    >>> than StringBuffer. So, in my code, I changed all StringBuffer usages to
    >>> StringBuilder. But now the performance has worsened. Is it that
    >>> StringBuffer is really more performant? Also, is there any better
    >>> performant way than using StringBuilder & StringBuffer?

    >>
    >> By "performant," I think you mean "performing." :)
    >>
    >> StringBuffer is supposed to be thread-safe. Since StringBuilder
    >> offers no such guarantee, it is potentially much faster. I don't
    >> think we're talking about a difference in big-O complexity, though,
    >> just a constant factor speed difference.
    >>
    >>
    >> Hmmm... A quick test makes this it look an awful lot like
    >> StringBuilder has *more* overhead, but is using a better algorithm.
    >> Odd. The code is below: For 1024 iterations, I got the same result
    >> you did, i.e. StringBuffer gave better performance:

    >
    > The actual performance is going to be very dependent on the operation
    > mix. A variation of your program suggests that some of the effects may
    > be due to outside influences such as page faulting or cache missing. I
    > modified the program to do each test multiple times, alternating:
    >
    > StringBuffer: 3255575 ns
    > StringBuilder: 6224512 ns
    > StringBuffer: 3741265 ns
    > StringBuilder: 2922576 ns
    > StringBuffer: 296705 ns
    > StringBuilder: 229733 ns
    > StringBuffer: 186285 ns
    > StringBuilder: 148315 ns
    > StringBuffer: 1421934 ns
    > StringBuilder: 149066 ns
    > StringBuffer: 181475 ns
    > StringBuilder: 145825 ns
    > StringBuffer: 192282 ns
    > StringBuilder: 143341 ns
    > StringBuffer: 185336 ns
    > StringBuilder: 151989 ns
    >
    > The first two lines look as though StringBuffer is faster than
    > StringBuilder, but the later lines suggest the opposite. I assume this
    > behavior is unrelated to the real program issue.


    That makes sense. String modification is so pervasive in actual
    programs... It's hard to come up with test cases that mimic the Wild.
     
    Jeffrey Schwab, Aug 24, 2006
    #4
  5. Patricia Shanahan wrote:
    >
    > The first two lines look as though StringBuffer is faster than
    > StringBuilder, but the later lines suggest the opposite. I assume this
    > behavior is unrelated to the real program issue.


    There is a lot of work going on behind the scenes to load your program
    even before it starts off on the first iteration. Most of the Java
    library is still using StringBuffer. Therefore, it seems likely that the
    StringBuffer code is mostly compiled while the StringBuilder starts off
    interpreted.

    Tom Hawtin
    --
    Unemployed English Java programmer
    http://jroller.com/page/tackline/
     
    Thomas Hawtin, Aug 24, 2006
    #5
  6. Patricia Shanahan wrote:
    > The actual performance is going to be very dependent on the operation
    > mix.


    I have a StringBuffer test program that do a mix of append and
    substring combined with some String operations.

    StringBuffer results says 1.11 while StringBuilder
    results say 1.18 on 32 bit Win32 SUN Java 1.5.

    (code attached in StringBuilder incarnation below for the curious)

    That is a 6% difference.

    I am not surprised that the difference is not bigger.

    The synchronized overhead has become smaller in newer
    JVM's.

    And the code do other things than just StringB*
    operations. But so do real world applications.

    Arne

    ===================================================

    import java.text.NumberFormat;
    import java.text.DecimalFormat;
    import java.util.Random;

    public class JvmTest {
    private final static int REP = 10;
    private final static int NSTR = 100;
    private final static int N = 1000000;
    private final static String ALFA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static NumberFormat nf = new DecimalFormat("0.00");
    private static Random rng = new Random();
    private static int scale;
    private static void printres(long t1, long t2, int n1, int n2,
    String ops) {
    double xperf = (double)n1 * (double)n2 / ((t2 - t1) / 1000.0) ;
    String sperf= nf.format(xperf/1000000);
    System.out.println(sperf + " million " + ops + " per second");
    }
    public static void teststr() {
    int nstrscale = NSTR / scale;
    long t1 = System.currentTimeMillis();
    for(int i = 0; i < nstrscale; i++) {
    StringBuilder sb = new StringBuilder("");
    for(int j = 0; j < N; j = j + 10) {
    String s = ALFA + ALFA;
    int ix = (i + j) % ALFA.length();
    sb.append(s.substring(ix, ix + 1) + s.substring(ix + 1,
    ix + 3) + s.substring(ix + 3, ix + 6) + s.substring(ix + 6, ix + 10));
    }
    int ix = rng.nextInt(N);
    if(sb.length() != N || sb.charAt(ix) != ALFA.charAt((i +
    ix) % ALFA.length())) {
    System.out.println("String test error");
    System.exit(0);
    }
    }
    long t2 = System.currentTimeMillis();
    printres(t1, t2, nstrscale, N / 10, "string operations");
    }
    public static void main(String[] args) {
    System.out.println(System.getProperty("java.vm.vendor") + " " +
    System.getProperty("java.vm.name") + " " +
    System.getProperty("java.vm.version"));
    if(args.length > 0) {
    scale = Integer.parseInt(args[0]);
    } else {
    scale = 1;
    }
    for(int i = 0; i < REP; i++) {
    teststr();
    }
    }
    }
     
    =?ISO-8859-1?Q?Arne_Vajh=F8j?=, Aug 25, 2006
    #6
  7. Raga

    ajrobb

    Joined:
    Apr 5, 2007
    Messages:
    2
    Missing the point

    Both StringBuffer and StringBuilder perform best if you can estimate the likely maximum size. The following code is a slight adaptation of previous poster's test code (although it is 4 times faster by pre-allocating, re-using and using StingBu*er to do ALL the appends).

    I get StringBuilder about 3% faster than StringBuffer (although the maximum performance of StringBuffer is no worse than the minum performance of StringBuilder). This is nothing compared with the 400% from code changes!

    I have not tried performance in a multi-threaded program. This is where synchronization overhead could kick in with StringBuffer.

    import java.text.NumberFormat;
    import java.text.DecimalFormat;
    import java.util.Random;

    public class JvmTest {
    private final static int REP = 5;

    private final static int NSTR = 100;

    private final static int N = 1000000;

    private final static String ALFA = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    private static NumberFormat nf = new DecimalFormat("0.00");

    private static Random rng = new Random();

    private static int scale;

    public static void main(String[] args) {
    System.out.println(System.getProperty("java.vm.ven dor") + " "
    + System.getProperty("java.vm.name") + " "
    + System.getProperty("java.vm.version"));
    if (args.length > 0) {
    scale = Integer.parseInt(args[0]);
    } else {
    scale = 1;
    }
    for (int i = 0; i < REP; i++) {
    teststr();
    }
    }

    private static void printres(long t1, long t2, int n1, int n2, String ops) {
    double xperf = (double) n1 * (double) n2 / ((t2 - t1) / 1000.0);
    String sperf = nf.format(xperf / 1000000);
    System.out.println(sperf + " million " + ops + " per second");
    }

    public static void teststr() {

    // replace with StringBuilder or StringBuffer
    // NOTE: it starts at the correct size!
    StringBuffer sb = new StringBuffer(N);
    String s = ALFA + ALFA;
    int nstrscale = NSTR / scale;
    long t1 = System.currentTimeMillis();
    for (int i = 0; i < nstrscale; i++) {
    sb.setLength(0); // re-use large object
    for (int j = 0; j < N; j = j + 10) {
    int ix = (i + j) % ALFA.length();
    // perform multiple appends
    sb.append(s.substring(ix, ix + 1));
    sb.append(s.substring(ix + 1, ix + 3));
    sb.append(s.substring(ix + 3, ix + 6));
    sb.append(s.substring(ix + 6, ix + 10));
    }
    int ix = rng.nextInt(N);
    if (sb.length() != N
    || sb.charAt(ix) != ALFA.charAt((i + ix) % ALFA.length())) {
    System.out.println("String test error");
    System.exit(0);
    }
    }
    long t2 = System.currentTimeMillis();
    printres(t1, t2, nstrscale, N / 10, "string operations");
    }
    }
     
    ajrobb, Apr 5, 2007
    #7
  8. Raga

    ajrobb

    Joined:
    Apr 5, 2007
    Messages:
    2
    For the original test in JVM HotSpot 1.6:
    StringBuffer: 187841472 ns
    StringBuilder: 144423663 ns
     
    ajrobb, Apr 5, 2007
    #8
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. IcYdRIP
    Replies:
    1
    Views:
    600
    IcYdRIP
    Apr 21, 2005
  2. Mike
    Replies:
    3
    Views:
    1,874
  3. Vince C.
    Replies:
    2
    Views:
    5,754
    Vince C.
    Jun 30, 2003
  4. Replies:
    1
    Views:
    492
    =?Utf-8?B?UGV0ZXIgQnJvbWJlcmcgW0MjIE1WUF0=?=
    Jul 14, 2006
  5. Wojtek
    Replies:
    80
    Views:
    2,549
    Tom Anderson
    Oct 11, 2009
Loading...

Share This Page