Java StringBuilder神话被揭穿
神話
用加號運算符連接兩個字符串是萬惡之源
-匿名Java開發人員
注意 :此處討論的測試的源代碼可以在Github上找到
從大學時代起,我就學會了使用+運算符將Java中的String連接視為致命的性能缺陷。 最近,在Backbase R&D上進行了一次內部審查,其中每當您使用plus運算符連接String時,由于在javac使用StringBuilder javac ,這種重復的口頭禪就被當作神話了。 我準備證明這一點并驗證不同環境下的現實。
考試
依靠編譯器優化String串聯意味著根據您采用的JDK供應商,情況可能會發生重大變化。 就我日常工作所需的平臺支持而言,應考慮三個主要供應商:
- Oracle JDK
- IBM JDK
- ECJ-僅適用于開發人員
此外,盡管我們正式支持Java 5至6,但我們也正在考慮為我們的產品提供Java 7支持,在這三個供應商的基礎上增加了另外三層的間接。 為了 懶惰 為簡單起見, ecj編譯的字節碼將使用單個JDK(即Oracle JDK7)運行。 我準備了安裝了上述所有JDK的Virtualbox VM,然后開發了一些類來表示三種不同的串聯方法,根據特定的測試用例,每種方法調用總計三至四個串聯。 每個測試回合都運行測試類數千次,每個測試用例總共進行100回合。 相同的VM用于運行同一測試用例的所有回合,并跨不同的測試用例重新啟動,所有這些都使Java運行時能夠執行所有可能的優化,而不會以任何方式影響其他測試用例。 缺省選項用于啟動所有JVM。 可以在基準運行程序腳本中找到更多詳細信息。
編碼
Github上提供了測試用例和測試套件的完整代碼。 產生了以下不同的測試用例,以測量String串聯的性能差異,加上直接使用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 an initialized StringBuilder new StringBuilder('const1').append(base).append('const2').append(append).toString();一般的想法是在變量的常量String的開頭和結尾都提供一個串聯。 后兩種情況(兩者都顯式使用StringBuilder之間的區別在于后者使用1-arg構造函數,該構造函數使用結果的初始部分初始化構建器。
結果
足夠多的討論,您可以在下面查看生成的圖形,其中每個數據點對應一個測試回合(例如,同一測試類的1000次執行)。 隨后將討論結果以及更多細節。
討論
甲骨文JKD5顯然是輸家,與其他甲骨文相比似乎處于B聯賽。 但這實際上不是本練習的范圍,因此我們暫時將其忽略。 也就是說,我在上圖中觀察到了另外兩個有趣的地方。 首先是,使用加號運算符與使用顯式StringBuilder通常確實存在很大的差異, 尤其是如果您使用的Oracle Java5的執行樹時間比其他工作人員差的話。
第二個觀察結果是,雖然對于大多數JDK來說,顯式StringBuilder通常提供的速度是常規plus運算符的兩倍,但IBM JDK6似乎不會遭受任何性能損失,它總是平均需要25ms才能完成任務。所有測試用例。 仔細查看生成的字節碼會發現一些有趣的細節
字節碼
注意:反編譯類也可以在Github上使用。在所有可能的JDK中,即使存在加號, StringBuilders 始終用于實現String串聯。 而且,在所有廠商和版本中,同一測試用例幾乎沒有任何區別 。 唯一的區別是ecj ,這是唯一巧妙地優化CatPlus測試用例以調用StringBuilder的1-arg構造函數而不是0-arg版本的方法。
比較生成的字節碼可以揭示在不同場景下可能影響性能的因素:
- 與plus串聯時,只要發生串聯,就會創建StringBuilder新實例 。 由于構造函數的無用調用,這很容易導致性能下降,并且由于丟棄實例而給垃圾收集器帶來更多壓力
- 如果且僅當您在原始代碼中以這種方式編寫StringBuilder ,編譯器才會照搬您,并且僅使用String的1-arg構造函數來初始化StringBuilder 。 這分別導致對CatSB和CatSB2的StringBuilder.append四個和三個調用。
結論
字節碼分析為原始問題提供了最終答案。 您是否需要顯式使用StringBuilder來提高性能? 是上面的圖清楚地表明,除非使用IBM JDK6運行時,否則在使用plus運算符時,您將損失50%的性能,盡管在顯式StringBuilder時,它在候選對象上的表現會稍差一些。 同樣,看到JIT優化如何影響整體性能也很有趣:例如,即使在兩個顯式StringBuilder測試用例之間存在不同的字節碼,從長遠來看,最終結果也絕對相同。
參考: Java StringBuilder神話從我們的JCG合作伙伴 Carlo Sciolla在Skuro博客中揭穿 。
翻譯自: https://www.javacodegeeks.com/2013/03/java-stringbuilder-myth-debunked.html
總結
以上是生活随笔為你收集整理的Java StringBuilder神话被揭穿的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Apache CXF – JAX-WS
- 下一篇: 心形怎么画 心形简笔画教程