我有一个基准:
@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
创造了什么魔力?
发布于 2017-02-13 09:02:04
正如您所提到的,HotSpot JVM具有-XX:+OptimizeStringConcat
优化,可以识别StringBuilder模式并将其替换为高度调优的手写IR图,而String.valueOf()
则依赖于常规的编译器优化。
通过分析生成的汇编代码,我发现了以下关键区别:
与任何其他常规object.
char[]
数组置零,而Integer.toString
创建的数组在分配后会被清除,而Integer.getChars
使用table lookup和相关的数组边界检查等。在PhaseStringOpts::int_getChars
和Integer.getChars
的实现中还有其他一些细微的差异,但我猜它们对性能并不是很重要。
顺便说一句,如果你接受一个更大的数字(例如1234567890),性能差异将可以忽略不计,因为Integer.getChars
中的extra loop一次可以转换两位数字。
https://stackoverflow.com/questions/42193955
复制相似问题