当在 Java 中使用 StringBuilder 时仍然创建 String 时,String builder 如何创建可变对象? [英] How does String builder create mutable object , when String is still created when using StringBuilder in Java?
问题描述
由于大量字符串,我们的应用程序面临非常糟糕的性能损失:创建用于记录应用程序状态.我们计划至少为记录器迁移到 String builder.我的一个困惑是:
We are facing very bad performance hit in our application due to large number of strings : created to log application state. We are planing to move to String builder at least for the logger. One confusion I have is :
因为字符串生成器被这样调用:
As string builder is called as such :
StringBuilder sb = new StringBuilder();
sb.append("Very big String object....");
如果我是对的,非常大的字符串对象...."仍然是一个构造函数,在内存中创建非常大的字符串对象(不可变),这些对象保留在字符串池中.
If I am right , "Very big String object...." is a still a constructor creating very large String object(immutable) in memory, which remain in String pool.
那么在这种情况下,String builder 的用途是什么?,因为它肯定会再创建一个对象,尽管会被垃圾收集.
So whats the use of String builder than in this case ?, as it will certainly create one more object , that will be though garbage collected.
但是使用 String 构造函数(双 qoutes)非常大的 String 对象...."创建的 String 仍在内存池中.
But the String that is created using String constructor (double qoutes) "Very big String object....", is still in memory pool.
推荐答案
StringBuilder
改进了多次添加的内存消耗和性能.让我们分析下一个例子(假设 javac 没有优化任何 String
连接):
StringBuilder
improves memory consumption and performance for multiple additions. Lets analyze next example (imagine that javac doesn't optimize any String
concatenations):
String s = "a" + "b" + "c" + "d" + ... + "z";
StringBuilder sb = new StringBuilder("a").append("b").append("c")....append("z");
如果 String
与 +
连接,java 会从左到右添加字符串,每次创建一个新字符串:"ab"
,然后是"abc"
,然后是"abcd"
,这样25个新的字符串,每次都会完全复制之前的结果.而 StringBuilder
只会将每个字符串添加到其自己的 char[]
数组中,而不会创建任何冗余对象.
In case of String
concatenation with +
java will add strings from left to right, creating a new string each time: "ab"
, then "abc"
, then "abcd"
, thus 25 new strings, and each time it will copy the previous result completely. While StringBuilder
will simply add each string to its own char[]
array, without any redundant objects creation.
现在让 n
是字符串的数量,而 l
- 每个字符串的长度.在这种情况下,第 m
个 +
的复杂度将是 O(l*m)
,因为每次都复制整个前面的字符串连接.因此我们可以得出结论,对于 String
情况,总结时间(和内存(!))复杂度将是 O(l*n*n)
.而在 StringBuilder
的情况下,它将是 O(l*n)
.
Now let n
be the number of strings, and l
- the length of each string. In this case the complexity of the m
th +
will be O(l*m)
, because each time the whole previous strings concatenation is copied. Thus we can make a conclusion that summary time (and memory (!)) complexity will be O(l*n*n)
for String
case. While in the case of StringBuilder
it will be O(l*n)
.
还有关于日志记录 - 小的性能比较:
Also regarding logging - small performance comparison:
@Benchmark
public void stringConcatenation(Blackhole bh) {
// By using all these string we should prevent string builder optimizations.
String a = "start ";
String b = a + "first";
String c = b + " inside ";
String d = c + "second";
String e = d + ", ";
String f = e + 1024;
bh.consume(a);
bh.consume(b);
bh.consume(c);
bh.consume(d);
bh.consume(e);
bh.consume(f);
}
@Benchmark
public void stringBuilder(Blackhole bh) {
StringBuilder sb = new StringBuilder("start ")
.append("first")
.append(" inside ")
.append("second")
.append(", ")
.append(1024);
bh.consume(sb.toString());
}
@Benchmark
public void logback(Blackhole bh) {
// Logback formatting
bh.consume(MessageFormatter.arrayFormat("start {} inside {}, {}", new Object[]{"first", "second", 1024}).getMessage());
}
@Benchmark
public void log4j(Blackhole bh) {
// Log4j formatting
bh.consume(messageFactory.newMessage("start {} inside {}, {}", "first", "second", 1024));
}
结果:
Benchmark Mode Cnt Score Error Units
LogBenchmark.stringConcatenation thrpt 5 9080147,269 ? 988134,269 ops/s
LogBenchmark.stringBuilder thrpt 5 27136050,849 ? 2776464,863 ops/s
LogBenchmark.logback thrpt 5 3579746,331 ? 346554,072 ops/s
LogBenchmark.log4j thrpt 5 4992342,169 ? 335971,537 ops/s
因此,正如您所看到的,如果您实际上需要进行大量日志记录,那么某些人建议改用日志记录框架格式化程序"可能不是更好的选择.
So as you can see suggested by some guys "use logging framework formatter instead" may not be the better choice if you are actually logging a lot.
这篇关于当在 Java 中使用 StringBuilder 时仍然创建 String 时,String builder 如何创建可变对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!