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燈, 水草

請輸入看板名稱,例如:Gossiping站內搜尋

TOP