为什么String连接比String.valueOf更快,以便将Integer转换为String?

时间:2017-02-12 22:17:04

标签: java performance microbenchmark

我有一个基准:

@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 StringConcatTest {

    private int aInt;

    @Setup
    public void prepare() {
        aInt = 100;
    }

    @Benchmark
    public String emptyStringInt() {
        return "" + aInt;
    }

    @Benchmark
    public String valueOfInt() {
        return String.valueOf(aInt);
    }

}

结果如下:

Benchmark                                          Mode  Cnt      Score      Error  Units
StringConcatTest.emptyStringInt                   thrpt   40  66045.741 ± 1306.280  ops/s
StringConcatTest.valueOfInt                       thrpt   40  43947.708 ± 1140.078  ops/s

它表明将空字符串与整数相连接比调用String.value(100)快30%。 我理解"" + 100转换为

new StringBuilder().append(100).toString()
应用

-XX:+OptimizeStringConcat优化,使其更快。我不明白的是为什么valueOf本身比串联慢。 有人可以解释究竟发生了什么以及为什么"" + 100更快。 OptimizeStringConcat有什么神奇之处?

1 个答案:

答案 0 :(得分:13)

正如您所提到的,HotSpot JVM具有-XX:+OptimizeStringConcat优化功能,可识别StringBuilder模式并将其替换为高度调整的手写IR图,而String.valueOf()依赖于通用编译器优化。

通过分析生成的汇编代码,我发现了以下关键差异:

  • 优化的concat不会为结果字符串创建零char[]数组,而Integer.toString创建的数组在分配后会像任何其他常规对象一样被清除。
  • 优化的concat通过简单的addition of '0' constant将数字转换为字符,而Integer.getChars使用table lookup和相关的数组边界检查等。

PhaseStringOpts::int_getCharsInteger.getChars的实施存在其他细微差别,但我认为它们对性能并不重要。

顺便说一句,如果你选择一个更大的数字(例如1234567890),性能差异可以忽略不计,因为Integer.getChars中的extra loop一次转换两位数。