"StringBuffer" and "String" performance competition

xiaoxiao2021-03-06  39

I saw the use of Cherami wrote

"String is still stringbuffer?" And a number of netizens behind, I feel that this problem is necessary to study hard, so I have written a simple test class and a script to run it. By modifying that test class as different parameters, and at different JDK tests discovery this problem is really a very interesting question. Let's get started below.

First step, ready to work

In order to facilitate the progress of the back test work, it is necessary to write 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 stringtest

Echo test by jdk1.3.1_09

/opt/java/jdk1.3.1_09/bin/javac StringTest.java

/opt/java/jdk1.3.1_09/bin/java stringtest

Echo test by jdk1.4.2

/opt/java/jdk1.4.2/bin/javac StringTest.java

/opt/java/jdk1.4.2/bin/java stringtest

The above scripts can be applied to Windows or Linux as needed, I am tested in Linux, so I save it as a file StringTest.sh, if you test it on Windows, you can save as StringTest.bat.

Note: The results of operation later are running multiple times and taken one more and typical sample values ​​for continuous operation.

Step 2, start writing code

At the beginning, I almost didn't think about it, I wrote 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" "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);

}

}

operation result:

Test by jdk1.2.2

Directly string Contact: 0

StringBuffer Contact: 120Test by jdk1.3.1_09

Directly string Contact: 1

StringBuffer Contact: 47

Test by JDK1.4.2

Directly string Contact: 0

StringBuffer Contact: 53

Oh, is it big out? ! ! ! I started, but don't worry, I actually made a mistake. Since the string operation is a string straight, the compiler is optimized when compiling, so string s = "this is a" "Long Test String for" "Different JDK Performance" "Testing."; String S = "this is a long test string for degecness jdk performance testing."; Oh, this is A simple assignment is operated, it is no wonder that the time used is almost gone.

Step 3, modify 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);

}

}

operation result:

Test by jdk1.2.2

Directly String Contact: 140

StringBuffer Contact: 123

TEST by jdk1.3.1_09

Directly string Contact: 32

StringBuffer Contact: 21

Test by JDK1.4.2

Directly String Contact: 48

StringBuffer Contact: 37

From the above results, we can indeed get the conclusions "use String or StringBuffer?", And it can also be seen that the difference in performance of different JDK versions is still relatively large, and the performance of JDK1.2.2 is the worst, while JDK1. 3.1 The performance is best. Is the discussion end? Oh, don't worry, it is far from the end. :)

In the fourth step, reduce the number of cycles (from 10,000 to 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);

}

}

operation result:

Test by jdk1.2.2

Directly String Contact: 12

StringBuffer Contact: 19

TEST by jdk1.3.1_09

Directly String Contact: 9

StringBuffer Contact: 13

Test by JDK1.4.2

Directly String Contact: 12

StringBuffer Contact: 18

What did you see? The above conclusions are overthrown, and the performance of the string direct connection operation is better than using StringBuffer, whether in that version of JDK, and in JDK1.3.1 performance is still the highest. We can't help but want to ask why. Unfortunately, I don't know why. My idea is that the difference between the two programs is primarily on the number of cycles, and the number of times the number of times, the number of objects that is created is different, and the other is different from the number of runs, which leads to JIT to operate. Optimization The intensity is different. These two factors are just the factors I think that the program results will definitely have an impact, but how it affects, I don't know.

Here, maybe our story is over, but from the above results, I feel that there is necessary to do some tests.

The fifth step, string all the intermediate results

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 = S1 S2 S3 S4;

}

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);

}

}

operation result:

Test by jdk1.2.2

Directly string Contact: 997

StringBuffer Contact: 13

TEST by jdk1.3.1_09

Directly String Contact: 1900

StringBuffer Contact: 21

Test by JDK1.4.2

Directly string Contact: 2157

StringBuffer Contact: 11

We finally see the huge advantage of using StringBuffers! And you may pay attention to a very interesting phenomenon: JDK1.3.1's performance seems to be not prominent here, in StringBuffer, even the worst. Very interesting, isn't it?

The sixth step, reducing the number of cycles again (500 times from 1000 times)

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 = S1 S2 S3 S4;

}

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);

}

}

operation result:

Test by jdk1.2.2

Directly String Contact: 270

StringBuffer Contact: 9

TEST by jdk1.3.1_09

Directly string Contact: 251

StringBuffer Contact: 2

Test by JDK1.4.2

Directly String Contact: 264

StringBuffer Contact: 2

Oh, the performance advantage of JDK1.3.1 is coming back! Moreover, the performance gap between the direct operation of the string is reduced compared to 1000 cases.

And it is only a sample value given above. If you run a few times, you will find the following phenomenon: JDK1.2.2 and JDK1.3.3 running time is almost every time, but JDK1.4.2 StringBuffer operation The fluctuations of running time are relatively large, and the fluctuations in my environment are actually between 1 and 16!

The story is here, I don't want to continue to do more tests, there is no bad conclusion in my mind, and we need to summarize the results of our experiment.

to sum up

I feel that some experiments from above, we can get some conclusions:

1.String operation and StringBuffer does not have absolute performance issues, but the conclusion that can be obtained, whether in that version of JDK, if it is the connection content very large, and the number of times the code is executed, then don't Herd, using StringBuffer, this performance difference is very big. If it is a shorter connection, then use the way you like, their performance has no significant difference.

2. Different versions of JDK have different optimizations made by these two operations. Overall, JDK1.3.1 is better to optimize them.

I want to remind you that don't get the following conclusion:

The performance of JDK1.3.1 is the best. Our conclusions are only for our testing, for other problems, how the performance of JDK1.3.1 is unknown, but I believe that the overall performance of JDK1.3.1 is better than JDK1.2.2.

I want to remind everyone that the last thing to pay is:

1. Don't blindly believe in performance optimization, use a sentence I have seen in an article in JR, saying: Only in you know that it is indeed a performance bottleneck to optimize.

2. The different versions of JDK have some running and compilation optimization in some respects, but this optimization is not fixed, we don't want to give too much expectations for those optimizations, the most fundamental or your code performance .

Reviews

Discuss: Firebox

I think the landlord cannot indicate performance differences in this test. Java applications are not simple from what you said. A virtual machine is in the long-term operation process, involving the management of memory, operation is clearly an increase in objects, more and more memory garbage will, and when concurrent requests, I think the situation may be worse! Guest: JSYX

There is no doubt that tests.

The meaning of StringBuffer is not only on the connection speed.

From the perspective of the server, the meaning of StringBuffer is that there can be generated more garbage objects than direct connection. To know that the number of GC runs / time is reduced, it is significant for a fast and long-term running program.

Discussant: Wolfsquare

After remarkably, I found a question, which is not accurate according to my personal experience. The value obtained by using JVM is inaccurate. At least 100 milliseconds, it is not accurate. It is recommended that the author has similar tests. Do more, take their average.

Reviews: Ljdrer

Oh, it may not be the purpose of this test, in fact, the initial purpose is because the above requirements cannot use the string operation, because the performance is not good, and he has indeed seen some Articles and books have said that this is really a problem, but later thinking that JDK is constantly optimized, so this issue may no longer exist.

Here to supplement the purpose of the test:

It is only:

String s = S1 S2 S3 S4;

And StringBuffer Buffer = new stringbuffer ();

Buffer.Append (S1);

Buffer.Append (S2);

Buffer.Append (S3);

String s = buffer.tostring ();

The performance difference between the program is to enlarge this difference, otherwise how big can the difference between the execution time of a statement? ?

Reviews: Ljdrer

To wolfsquare: The original statement is very clear:

"The results in this article are running multiple times and take one of the average and typical sample values.

Therefore, there should be no problem you say.

Discussant: 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), The DEFAULT VALUE IS 16?) 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.

Guest: FinaAlarrow

You tried to set the length of StringBuffer when you initially instant StringBuffer (of course, it is better than the result string of the test), what results do you have? I haven't tried it, but there is an article to discuss this. After setting the length, StringBuffer doesn't have to share the address every time, the speed will be very fast.

This is the same as the principle of Vector.

转载请注明原文地址:https://www.9cbs.com/read-51778.html

New Post(0)