"StringBuffer" and "String" quality competition

  Read cherami wrote "String or StringBuffer?" Behind the number of netizens, as well as the comments, I feel this issue is necessary to properly investigate, prepared a simple test category and a script to run it.    Laws passed that test parameters for different categories, and in different JDK testing discovered the problem really is a very interesting question.    Let's get started. 

  First step in the preparatory work 

  In order to facilitate the work of the latter test, it is necessary to prepare a simple script: 

  Echo test by jdk1.2.2/opt/java/jdk1.2.2/bin/javac StringTest.java/opt/java/jdk1.2.2/bin/java StringTestecho test by jdk1.3.1_09/opt/java/jdk1.3.1_09 / bin / javac StringTest.java/opt/java/jdk1.3.1_09/bin/java StringTestecho test by jdk1.4.2/opt/java/jdk1.4.2/bin/javac StringTest.java/opt/java/jdk1.4.2/bin / java StringTest 



  According to the above script needs can be applied to windows or linux, I conducted tests in linux, so I kept it as a document stringtest.sh, if you windows on the test, you can save for stringtest.bat. 

  Note: In this paper, the results are running behind the continuous operation and many of them take a more typical sample and the average value) 

 
The second step, began to write code 

  The first I almost did not consider how to write the following code: 

  Public class StringTest (public static void main (String [] args) (long start = System.currentTimeMillis (); for (int i = 0; i <10000; i + +) (String s = "This is a" + "long test string for the "+" different JDK performance "+" testing. ";) long end = System.currentTimeMillis (); System.out.println (" Directly string contact: "+ (end-start)); start = System.currentTimeMillis (); for (int i = 0; i <10000; i + +) (StringBuffer buffer = new StringBuffer (); buffer.append ( "This is a"); buffer.append ( "long test string for"); buffer. append ( "different JDK performance"); buffer.append ( "testing."); String ss = buffer.toString ();) end = System.currentTimeMillis (); System.out.println ( "StringBuffer contact:" + ( end-start));)) 



  The result: 

  Test by jdk1.2.2Directly string contact: 0StringBuffer contact: 120test by jdk1.3.1_09Directly string contact: 1StringBuffer contact: 47test by jdk1.4.2Directly string contact: 0StringBuffer contact: 53 



  Oh, is not a big accident?    !    !    !    I also started, but Do not, in fact I made a mistake, as a result of the string + direct operation of the string are, in the compiler to compile time optimization, String s = "This is a" + "long test string for the" + "different JDK performance" + "testing."; compiled after a fact: String s = "This is a long test string for different JDK performance testing.";, Oh, this is a simple assignment, and no wonder the time spent almost no. 

 
The third step is to amend the code 

  Public class StringTest (public static void main (String [] args) (String s1 = "This is a" String s2 = "long test string for" String s3 = "different JDK performance" String s4 = "testing." ; long start = System.currentTimeMillis (); for (int i = 0; i <10000; i + +) (String s = s1 + s2 + s3 + s4;) long end = System.currentTimeMillis (); System.out.println ( "Directly string contact:" + (end-start)); start = System.currentTimeMillis (); for (int i = 0; i <10000; i + +) (StringBuffer buffer = new StringBuffer (); buffer.append (s1 ); buffer.append (s2); buffer.append (s3); buffer.append (s4); String ss = buffer.toString ();) end = System.currentTimeMillis (); System.out.println ( "StringBuffer contact : "+ (end-start));)) 



  The result: 

  Test by jdk1.2.2Directly string contact: 140StringBuffer contact: 123test by jdk1.3.1_09Directly string contact: 32StringBuffer contact: 21test by jdk1.4.2Directly string contact: 48StringBuffer contact: 37 



  Looking at the results from the above we really can be "use String or StringBuffer?" In the conclusions, but also can see the different versions of the JDK performance difference is quite large, the performance of the worst JDK1.2.2 and JDK1. 3.1 the best performance. 

  The end of the discussion?    Oh, Buyaoji, it is far from ending.    :) 

 
The fourth step is to reduce cycle times (from 10,000, a 1000) 

  Public class StringTest (public static void main (String [] args) (String s1 = "This is a" String s2 = "long test string for" String s3 = "different JDK performance" String s4 = "testing." ; long start = System.currentTimeMillis (); for (int i = 0; i <1000; i + +) (String s = s1 + s2 + s3 + s4;) long end = System.currentTimeMillis (); System.out.println ( "Directly string contact:" + (end-start)); start = System.currentTimeMillis (); for (int i = 0; i <1000; i + +) (StringBuffer buffer = new StringBuffer (); buffer.append (s1 ); buffer.append (s2); buffer.append (s3); buffer.append (s4); String ss = buffer.toString ();) end = System.currentTimeMillis (); System.out.println ( "StringBuffer contact : "+ (end-start));)) 



  The result: 

  Test by jdk1.2.2Directly string contact: 12StringBuffer contact: 19test by jdk1.3.1_09Directly string contact: 9StringBuffer contact: 13test by jdk1.4.2Directly string contact: 12StringBuffer contact: 18 



  What do you see?    The above conclusion has been overthrown, the direct link to the operation of the string of StringBuffer than the use of the good performance, whether it is in that version of the JDK, but also in the performance JDK1.3.1 still is the highest.    We can not but ask why.    I regret that I do not know why.    My idea is above the main difference between the two procedures is that the number of recycling, and the number of different led to the creation of the number of objects is the use of different memory, a different number of different operations is a result of JIT to the run-time optimization Strength different.    These two factors I think that the only outcome of the proceedings, there will certainly be affected, but the impact is, I do not know. 

  To here, maybe we have the end of the story, but from the above results, I feel the need to do some tests. 

 
Step 5, the intermediate results of all string together 

  Public class StringTest (public static void main (String [] args) (String s1 = "This is a" String s2 = "long test string for" String s3 = "different JDK performance" String s4 = "testing." ; long start = System.currentTimeMillis (); String s = ""; for (int i = 0; i <1000; i + +) (s + + s2 = s1 + s4 + s3;) long end = System.currentTimeMillis (); System.out.println ( "Directly string contact:" + (end-start)); start = System.currentTimeMillis (); StringBuffer buffer = new StringBuffer (); for (int i = 0; i <1000; i + +) ( buffer.append (s1); buffer.append (s2); buffer.append (s3); buffer.append (s4); String ss = buffer.toString ();) end = System.currentTimeMillis (); System.out. println ( "StringBuffer contact:" + (end-start));)) 



  The result: 

  Test by jdk1.2.2Directly string contact: 997StringBuffer contact: 13test by jdk1.3.1_09Directly string contact: 1900StringBuffer contact: 21test by jdk1.4.2Directly string contact: 2157StringBuffer contact: 11 



  We finally see the great advantages of the use of StringBuffer!    And you may also be noted that a very interesting phenomenon: JDK1.3.1 the performance of a performance here seems not so conspicuous. StringBuffer even in the worst performance in the.    Very interesting, is not it? 

 
Step 6, and again reduce cycle times (from the 1000 reduction of 500) 

  Public class StringTest (public static void main (String [] args) (String s1 = "This is a" String s2 = "long test string for" String s3 = "different JDK performance" String s4 = "testing." ; long start = System.currentTimeMillis (); String s = ""; for (int i = 0; i <500; i + +) (s + + s2 = s1 + s4 + s3;) long end = System.currentTimeMillis (); System.out.println ( "Directly string contact:" + (end-start)); start = System.currentTimeMillis (); StringBuffer buffer = new StringBuffer (); for (int i = 0; i <500; i + +) ( buffer.append (s1); buffer.append (s2); buffer.append (s3); buffer.append (s4); String ss = buffer.toString ();) end = System.currentTimeMillis (); System.out. println ( "StringBuffer contact:" + (end-start));)) 



  The result: 

  Test by jdk1.2.2Directly string contact: 270StringBuffer contact: 9test by jdk1.3.1_09Directly string contact: 251StringBuffer contact: 2test by jdk1.4.2Directly string contact: 264StringBuffer contact: 2 



  Oh, JDK1.3.1 advantage of the performance is back!    And 1000 and compared with the situation, string operations directly reduces the performance gap. 

  And the above is just a sample of value, if you run several more will be found as follows phenomenon: JDK1.2.2 and JDK1.3.3 run time in each run almost all the time, but the StringBuffer operations JDK1.4.2 running time on a larger fluctuations, in my environment even in the scope of fluctuation between 1-16! 

  Story here, I do not want to continue to do more tests, my mind there is no good who have bad conclusions, we need to sum up what we have the results of the above experiments. 

 
Aggregate 

  I feel that from the above experiments, we can get some of the conclusions are as follows: 

  1.String + StringBuffer operations and the performance absolutely does not exist, but can come to the conclusion that, regardless of the version of the JDK that, if the link is very large and multinational, and the code is executed many times, then not hesitation, the use of StringBuffer, the performance difference is significant.    If the link is relatively short, so use it the way you like, their performance there was no obvious difference. 

  2. Different versions of the JDK these two operations done optimization is different, in general, JDK1.3.1 of their optimization is quite good. 

  I would like to remind you is not to reach the following conclusions: 

  JDK1.3.1 performance is the best.    Our conclusion is for us to test the problem, other issues, the performance of JDK1.3.1 to know, but I believe that the overall performance of JDK1.3.1 better than some JDK1.2.2. 

  Finally I would like to remind everyone the attention of the matter is: 

  1. Should not blindly believe that performance optimization, in the past, I used a JR inside of an article that said: Only you know it is indeed only where performance bottlenecks to optimize. 

  2.JDK for some of the different versions of certain aspects of the operation and a number of compiler optimization, but this optimization is not fixed, and we should not place too much on the optimization of those expectations, the most fundamental of the performance of your code . 

  User Reviews 

  Comments: firebox 

  I think that the landlord can not use such a test to show that performance differences.    Java application is not simply from what you said in terms of this.    A virtual machine in the course of long-term, is related to memory management, + operator is obviously an increase of object, the memory will be more and more garbage, and when the concurrent request, I think the situation may be even worse! 

  Guests: jsyx 

  There is no doubt test. 

  StringBuffer with the significance not only in the connection speed. 

  From the server's point of view, the significance lies with StringBuffer can produce less than more directly connected to the refuse object.    Need to know the number of operating gc / time, the reduction of the long-term operation of a fast procedure is significant 

  Comments: wolfsquare 

  Re-read this and found a problem, according to my personal experience in the use of jvm currentTimeMillis () method to get the value is inaccurate, at least in the level of 100 ms is not accurate. Author of a similar proposal if the test so many times, they take the average. 

  Comments: ljdrer 

  Oh, may not be clear in the beginning that what the purpose of this test is the initial purpose of the project because of the time required above do not use the + string operation because of bad, but his past is also seen some articles and books said that this is indeed a problem, but later thought JDK is ongoing optimization This issue, therefore, may not exist. 

  Add here that the purpose of this test: 

  To test simply is: 

  String s = s1 + s2 + s4 + s3; and StringBuffer buffer = new StringBuffer (); buffer.append (s1); buffer.append (s2); buffer.append (s3); buffer.toString String s = (); 



  Performance differences between the procedures cycle is the reason for this difference in order to enlarge it, or else the implementation of a sentence of time how much difference can there?    ? 

  Comments: ljdrer 

  To wolfsquare: Original beginning has been said very clearly: 

  "In this paper, the results are behind the repeated and continuous operation from a comparison of the average and typical sample values" 

  So you say there should not be the issues now. 

  Comments: mosa 

  The methodology you mentioned is not fair enough. Given that you only run the loop with less than some hundred milliseconds, there're many factors that may bias the results. To name a few: 

  1. VM initialization, class loading and JIT time, which can easily amount to some 10 ms. If you test StringBuffer first and then String "+", the result may be different. You may first run both cases with a few loops and then begin real time collecting. 

  2. GC may take a few ms to some 10 ms, depends on different systems. For a collecting timeframe like some 10 ms, one more GC may contaminate the expected results. You may run Runtime.gc () before the StringBuffer test begins. But the behavior of Runtime.gc () may depend on different VMs. 

  For a modified step 3 and 4, you can conclude String "+" and StringBuffer append are with comparable performance. That's not surprising, because after you use "javap-c" to deassemble them into bytecode, you can find the two bytecode sequences are very similar (String "+" may even be more optimal in the bytecode level, because it utilizes StringBuffer.append 's return value for chained concatenation). StringBuffer has the advantage that you can specify the initial capacity with your knowledge in the context (the default value is 16?), then you can avoid many capacity expansion which further relaxes GC and arraycopy overhead. 

  Step 5 is totally different from 3 & 4. The String "+" part creates much more objects (at least one String and one StringBuffer per loop and many subsequent objects like char arrays) than StringBuffer part. "Javap-c" and "java-verbosegc "may help you solve the puzzle. 

  Guests: finalarrow 

  You try to instantiate StringBuffer in the initial set when the length of StringBuffer (of course, than the results of tests string larger), you try What will be the results?    I have tried, however, there is an article discussing this, and set up a length, each StringBuffer do not have to go compared to the size distribution of address, the speed will be much faster. 

  This Vector and the principle is the same. 

Recommend Articles

Comments

Leave a Reply