2012-07-03 66 views
3

以下Jsoup代碼連接的所有元素的文本在容器elsJava編譯器不會自動優化字符串連接嗎?

for (Element el : els) 
    entireText += el.text();   

在一個容器以〜64個元素,每個包含〜1KB(在entireText爲〜64KB共計),這個簡單的循環需要大約典型的低端Android手機上8秒

這種性能低下讓我感到驚訝,因爲我的印象是Java編譯器用A + B + Cnew StringBuilder(A).append(B).append(C).toString()替代表達式。

是不是這樣?

我錯過了什麼?

+0

你比較了兩個選項還是隻是猜測字符串連接是問題的根源? – home

+0

@home當然我比較。 StringBuilder選項在**不到1秒**內完成。 – Souper

+1

'javac'編譯器幾乎沒有優化。即使使用JIT,它也不會優化這些代碼。開發人員需要知道這是非常有效的。 –

回答

12

這種緩慢的性能那種讓我吃驚,因爲我是 印象是Java編譯像A + B + C 新的StringBuilder(A).append(B).append替代表情下(C)的ToString ()。

所以編譯器產生的代碼:

for (Element el : els) 
    entireText = new StringBuilder(entireText).append(el.text()).toString(); 

您需要創建外循環StringBuilder的手動追加到它。

+0

爲什麼不在每次迭代中追加** ** ** StringBuilder實例?你爲什麼每次迭代創建'新的StringBuilder'? – alaster

+0

@mlk啊好的。我認爲Java編譯器比這更聰明。 – Souper

+0

@alaster - 你應該創建一個StringBuilder。我的代碼是顯示編譯器在做什麼,而不是OP應該做什麼。 –

4

這裏的問題是,你的第一次迭代中創建一個字符串1K,第二創建一個字符串2K,第三創建一個字符串3K,...

每個字符串都需要創建前一個副本。所以你的第一次迭代複製1K文本,第二個副本2K,第三個副本3K,...

因此,每個迭代比前一個迭代更慢,最後一次迭代分配64k緩衝區並複製64k。

使用StringBuilder(作爲@mlk顯示)意味着你幾乎只分配一次64k(不夠,但足夠接近)並且只複製64k數據(與64k + 63k + 62k + 61k + 60k +相反)。 ..)。