Translate-CS 板


LINE

原文网址:http://skuro.tk/2013/03/11/java-stringbuilder-myth-now-with-content/ 译文网址:http://blog.dontcareabout.us/2013/04/java-stringbuilder.html BBS 版以 markdown 语法撰写 喔对,这篇真的不是愚人节活动 update: 不,这篇真的好像被愚人到了 详情请参阅 java 版的 #1HMQB1It 不过这篇就... 还是放着吧...... [死] ______________________________________________________________________ 谣言...... ========== > 用 + 号来连接两个字串是万恶的根源。 —— 不知名的 Java 开发人员 **注:**这里讨论用到的程式码都可以在 [Github] 上找到。 在大学的时候,我学到在 Java 中用 + 号来连接字串是一种致命的效能罪恶。 最近在 [Backbase R&D] 有一个内部的 review, 这个 recurring mantra 变成了谣言, 因为当你使用 + 号来连接字串时,`javac` 会在底层使用 `StringBuilder`。 我要证明这件事情,并验证在不同环境下的真实性。 [Github]: https://github.com/skuro/stringbuilder [Backbase R&D]: http://www.backbase.com/ 测试...... ========== 倚赖 compiler 对连接字串这件事作最佳化, 这意味着使用不同的 JDK 可能会得到完全不一样的结果。 就我平常的工作环境,我考虑这三个 JDK 供应商: * Oracle JDK * IBM JDK * ECJ(仅针对开发人员) 此外,虽然我们官方支援 Java 5 跟 Java 6, 不过我们也在研究让产品可以支援到 Java 7, adding another three-folded level of indirection on top of the three vendors.(译注:翻译不能 Orz) 为了<strike>懒惰</strike>简单起见, `ecj` compile 出来的 bytecode 只会在 Oracle JDK 7 上头执行。 我准备了一个 [VirtualBox] VM 安装上述所有的 JDK, 然後我写了一些 class 来代表三种不同的字串连接方式, 每一个 method 会有三到四个连接字串的动作、取决於 test case。 [VirtualBox]: https://www.virtualbox.org/ 这些 test case 在每一回合会执行一千次、总共 100 回合。 同一个 test 的所有回合都会在同一个 VM 上头执行, 在跑不同 test case 的时候重开 VM, 这都是为了让 Java 在执行期可以作任何可能的最佳化动作、 而不会影响到其他 test case。 所有 JVM 启动时都用预设的设定。 更细节的部份可以参考 benchmark runner [script]。 [script]: https://github.com/skuro/stringbuilder/blob/master/bench.sh 程式码 ====== 所有 test case 以及 test suite 的完整程式码都在 [Github] 上头。 下面这几个不同的 test case 用来测量 + 号与直接使用 `StringBuilder` 连接字串的效能差异: // String concat with plus String result = "const1" + base; result = result + "const2"; ______________________________________________________________________ // String concat with a StringBuilder new StringBuilder() .append("const1") .append(base) .append("const2") .append(append) .toString(); } ______________________________________________________________________ // String concat with a StringBuilder new StringBuilder("const1") .append(base) .append("const2") .append(append) .toString(); } 大体上的想法是在常数字串前後都连接一个变数。 最後两个 case 都是用 `StringBuilder`, 差异是後头使用了传入一个参数的 constructor, 在 builder 初始化的时候就初始化结果的一部分。 结果...... ========= 前提讲的差不多了,下面这些产生出来的图表, 每一个点对应到单一个测试回合(对同一个测试执行 1000 次)。 後头会讨这些结果以及一些有趣的细节。 ![plus](http://skuro.tk/img/post/catplus.png) ![StringBuffer()](http://skuro.tk/img/post/catsb.png) ![StringBuffer(String)](http://skuro.tk/img/post/catsb2.png) 讨论...... ========== Oracle JDK 5 输的很彻底,跟其他相比就是个 B 咖。 但那不是这次要讨论的范围,所以暂时不理会吧。 在上头的图表当中我观察到两件有趣的事情。 首先,使用 + 号跟明确指定用 `StringBuilder` 的确存在普遍的落差, *特别是*在使用 Oracle Java 5 的时候比其他人差了三倍。 第二个观察到的现象是,大多数的 JDK 在明确指定用 `StringBuilder 时可以提供比 + 号快两倍的速度, 而 **IBM JDK 6 看起来没有减损任何效能**, 在所有的 test case 中始终保持在 25ms 左右的时间。 仔细看一下产生出来的 bytecode 揭露了一些有趣的细节。 bytecode 表示: ============== **注:**[Github] 上也有 decompile 後的 class。 在所有的 JDK 上应该**总是**用 `StringBuilder` 来实作连接字串, 即使有 + 可以用。 此外,比较所有供应商的所有版本, 在同样的 test case 下**几乎没有什麽分别**。 唯一比较有区隔的是 [ecj],它是唯一一个对 `CatPlus` test case 作最佳化, 会使用传入一个参数的 `StringBuilder` constructor,而不是 `StringBuilder()`。 [ecj]: https://github.com/skuro/stringbuilder/blob/master/ecj/CatPlus.class.txt 比较产生的 bytecode 可以看到在不同情境下可能会影响效能的部份: * 用 + 号连接字串时,每一次都会建立一个**新的** `StringBuilder` **instance**。 这很容易导致效能下降,因为要产生一堆用完就丢 instance, 而造成 garbage collector 的压力。 * compiler 会依照字面上的意思, 只有在你指定用传入一个参数的 `StringBuilder` constructor, compiler 才会用它。 这分别导致 [CatSB] 呼叫了四次 `StringBuilder.append()`、 而 [CatSB2] 呼叫三次。 [CatSB]: https://github.com/skuro/stringbuilder/blob/master/ecj/CatSB.class.txt [CatSb2]: https://github.com/skuro/stringbuilder/blob/master/ecj/CatSB2.class.txt 结论...... ========= 分析 bytecode 提供了问题的最终答案: > 需要明确指定用 `StringBuilder` 来增进效能吗? > **是的!** 上面的图表显示的很清楚了,用 + 号会损失 50% 的效能; 除非你用 IBM JDK 6, 那只会笔明确指定使用 `StringBuilder` 稍微差一点点。 此外,看 *JIT 最佳化* 如何影响整体效能十分有趣。 例如:即使两个指定使用 `StringBuilder` 的 test case, 它们的 bytecode 看起来不一样, 但是长时间运作之後它们得到的结果还是几乎一样的。 ![confirmed](http://skuro.tk/img/post/myth-confirmed.jpg) -- 钱锺书: 说出来的话 http://www.psmonkey.org 比不上不说出来的话 Java 版 cookcomic 版 只影射着说不出来的话 and more...... --



※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 114.25.15.134 修正一些 typo ※ 编辑: PsMonkey 来自: 114.25.15.134 (04/01 22:14) ※ 编辑: PsMonkey 来自: 114.25.15.134 (04/01 23:10)







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:Soft_Job站内搜寻

TOP