当在 Java 中使用 StringBuilder 时仍然创建 String 时,String builder 如何创建可变对象? [英] How does String builder create mutable object , when String is still created when using StringBuilder in Java?

查看:79
本文介绍了当在 Java 中使用 StringBuilder 时仍然创建 String 时,String builder 如何创建可变对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于大量字符串,我们的应用程序面临非常糟糕的性能损失:创建用于记录应用程序状态.我们计划至少为记录器迁移到 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 mth + 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆