java – JMH puzzle:StringBuilder vs StringBand
我很难理解这个基准测试的进展情况.我想测量我的示例类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,destination,start,len); s.getChars(0,len,start); start += len; } return new String(destination); } } 此代码使用:UnsafeUtil.getChars()实际获取String char []而不复制,请参阅代码here.我们也可以使用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个字符时发生的事情的理解. StringBuilder的 >创建了新的字符[20 16](36个字符) StringBand >创建了新的String [2] 期望 使用StringBand,我们有: >少一个arraycopy – 这样做的目的是什么 所以我希望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或在代码中明确使用BlackHoles时,也会发生同样的情况. 为什么? 解决方法
好吧,像往常一样,“猫头鹰不是他们看起来的样子”.通过快速检查Java代码来推理代码性能变得奇怪.通过查看字节码来推理感觉是一样的.生成的代码反汇编应该对此有更多的了解,即使有一些小的情况下,程序集太高而无法解释这种现象.
这是因为平台在各个层面都大量优化了代码.这是你应该看的提示.在i5 2.0 GHz,Linux x86_64,JDK 7u40上运行您的基准测试. 基线: Benchmark Mode Thr Count Sec Mean Mean error Units j.b.s.StringBandBenchmark.stringBand2 thrpt 2 20 1 25800.465 297.737 ops/ms j.b.s.StringBandBenchmark.stringBuilder2 thrpt 2 20 1 55552.936 876.021 ops/ms 是的,令人惊讶.现在,看看这个.我的袖子里什么都没有,除了…… -XX:-OptimizeStringConcat: Benchmark Mode Thr Count Sec Mean Mean error Units j.b.s.StringBandBenchmark.stringBand2 thrpt 2 20 1 25727.363 207.979 ops/ms j.b.s.StringBandBenchmark.stringBuilder2 thrpt 2 20 1 17233.953 219.510 ops/ms 禁止VM进行字符串优化会产生“预期”结果,如原始分析中所述.众所周知,HotSpot具有StringBuilders的优化功能,可以有效识别新的StringBuilder().append(…).append(…).toString()等常用习惯用法,并为语句生成更有效的代码. 拆解并弄清楚应用的字符串优化究竟发生了什么,留给感兴趣的读者练习:) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |