我很难理解这个基准测试的进展情况.我想测量我的样本类的StringBand
工作方式StringBuilder
.这个想法StringBand
是连接字符串,而toString()
不是连接字符串append()
.
这是StringBand
源 - 剥离基准:
public class StringBandSimple { private String[] array; private int index; private int length; public StringBandSimple(int initialCapacity) { array = new String[initialCapacity]; } public StringBandSimple append(String s) { if (s == null) { s = StringPool.NULL; } if (index >= array.length) { //expandCapacity(); } array[index++] = s; length += s.length(); return this; } public String toString() { if (index == 0) { return StringPool.EMPTY; } char[] destination = new char[length]; int start = 0; for (int i = 0; i < index; i++) { String s = array[i]; int len = s.length(); //char[] chars = UnsafeUtil.getChars(s); //System.arraycopy(chars, 0, destination, start, len); s.getChars(0, len, destination, start); start += len; } return new String(destination); } }
此代码使用:UnsafeUtil.getChars()
实际获取String
char []而不复制,请参阅此处的代码.我们也可以使用getChars()
和它仍然相同.
这是JMH测试:
@State public class StringBandBenchmark { String string1; String string2; @Setup public void prepare() { int len = 20; string1 = RandomStringUtil.randomAlphaNumeric(len); string2 = RandomStringUtil.randomAlphaNumeric(len); } @GenerateMicroBenchmark public String stringBuilder2() { return new StringBuilder(string1).append(string2).toString(); } @GenerateMicroBenchmark public String stringBand2() { return new StringBandSimple(2).append(string1).append(string2).toString(); } }
这是我对添加两个字符串20个字符时发生的事情的理解.
new char[20+16]
创建(36个字符)
arraycopy
被称为复制20个string1
字符StringBuilder
在第二次追加之前,StringBuilder
扩大容量,因为40> 36
因此,new char[36*2+2]
创造了
arraycopy
20个字符到新的缓冲区
arraycopy
20个字符附加秒 string2
最后,toString()
回归new String(buffer, 0, 40)
new String[2]
被建造
两者都只是将字符串保留在内部缓冲区中,直到toString()
被调用
length
增加两次
new char[40]
已创建(结果字符串的总长度)
arraycopy
20个第一个字符串字符(UnsafeUtil
提供字符串的实际char[]
缓冲区)
arraycopy
20秒的字符串字符
最后,回归 new String(buffer, 0, 40)
随着StringBand
我们:
少一点arraycopy
- 这样做的目的是什么
减少分配规模:new String[]
和new char[]
两个new char[]
加上我们没有像StringBuilder
方法那样的很多检查(对于大小等)
所以我希望它StringBand
至少可以起作用StringBuilder
,如果不是更快的话.
我在2013年中期在MacBookPro上运行基准测试.使用JMH v0.2和Java 1.7b45
命令:
java -jar build/libs/microbenchmarks.jar .*StringBand.* -wi 2 -i 10 -f 2 -t 2
预热迭代次数(2)很好,因为我可以看到第二次迭代达到相同的性能.
Benchmark Mode Thr Count Sec Mean Mean error Units j.b.s.StringBandBenchmark.stringBand2 thrpt 2 20 1 37806.993 174.637 ops/ms j.b.s.StringBandBenchmark.stringBuilder2 thrpt 2 20 1 76507.744 582.131 ops/ms
结果说StringBuilder
是两倍快.当我将线程数增加到16或BlackHole
在代码中使用显式s时,也会发生同样的情况.
为什么?