【问题标题】:Why is the StringBuilder chaining pattern sb.append(x).append(y) faster than regular sb.append(x); sb.append(y)?为什么 StringBuilder 链接模式 sb.append(x).append(y) 比常规 sb.append(x) 快; sb.append(y)?
【发布时间】:2017-11-04 04:16:36
【问题描述】:

我有一个显示非常奇怪结果的微基准:

@BenchmarkMode(Mode.Throughput)
@Fork(1)
@State(Scope.Thread)
@Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS, batchSize = 1000)
@Measurement(iterations = 40, time = 1, timeUnit = TimeUnit.SECONDS, batchSize = 1000)
public class Chaining {

    private String a1 = "111111111111111111111111";
    private String a2 = "222222222222222222222222";
    private String a3 = "333333333333333333333333";

    @Benchmark
    public String typicalChaining() {
        return new StringBuilder().append(a1).append(a2).append(a3).toString();
    }

    @Benchmark
    public String noChaining() {
        StringBuilder sb = new StringBuilder();
        sb.append(a1);
        sb.append(a2);
        sb.append(a3);
        return sb.toString();
    }
}

我希望两个测试的结果相同或至少非常接近。但是,差异几乎是 5 倍:

# Run complete. Total time: 00:01:41

Benchmark                  Mode  Cnt      Score     Error  Units
Chaining.noChaining       thrpt   40   8538.236 ± 209.924  ops/s
Chaining.typicalChaining  thrpt   40  36729.523 ± 988.936  ops/s

有人知道这怎么可能吗?

【问题讨论】:

  • 也许它有一个针对链式 .append 调用的优化规则,它可以一次构造整个字符串?这很有意义。
  • @Mints97 编译器不应该对常规的 sb.append() 结构做同样的事情吗?
  • @JarrodRoberson 我的期望是完全正确的。你不会期待同样的吗?它几乎是相同的代码。即使链接生成的字节码也更少。 5倍的差距?没办法。
  • 有趣的是,如果您在关闭 JIT 的情况下运行此程序,它们将按预期工作。 (顺便说一句,-Djava.compiler=NONE)。每个基准测试的结果几乎相同(而且速度要慢得多)。
  • “我的期望是完全正确的”,但结果却不是你所期望的。你我对“完全正确”的定义不同。

标签: java performance microbenchmark jmh


【解决方案1】:

字符串连接a + b + c是Java程序中非常常见的模式,因此HotSpot JVM对其进行了特殊优化:-XX:+OptimizeStringConcat默认开启。

HotSpot JVM 识别字节码中的new StringBuilder().append()...append().toString() 模式并将其转换为优化的机器代码,而无需调用实际的 Java 方法,也无需分配中间对象。 IE。这是一种复合 JVM 内在函数。

这是用于此优化的source code

另一方面,sb.append(); sb.append(); ... 没有特殊处理。该序列的编译方式与常规 Java 方法调用一样。

如果您使用 -XX:-OptimizeStringConcat 重新运行基准测试,两种变体的性能将相同。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    • 2019-05-13
    • 1970-01-01
    相关资源
    最近更新 更多