2012-11-13 77 views
5

我寫了很多東西來登錄突發,並優化數據路徑。我使用StringBuilder構建日誌文本。什麼是最有效的初始容量,內存管理是明智的,所以無論JVM如何,它都能很好地工作。目標是幾乎總是避免重新分配,初始容量應該在80-100左右。但是我也想浪費盡可能少的字節,因爲StringBuilder實例可能會在緩衝區中出現並浪費字節。StringBuilder最有效的初始容量大小?

我意識到這取決於JVM,但應該有一些價值,這將浪費最少的字節,無論JVM,「最不共同的分母」。我目前使用128-16,其中128是一個不錯的整數,減法用於分配開銷。此外,這可能被認爲是「過早優化」的情況,但是由於我接下來的答案是「經驗法則」數字,因爲知道它在未來也會有用。

我並不期待「我最好的猜測」答案(我自己的答案已經是這樣),我希望有人已經研究過這個問題,可以分享一個基於知識的答案。

+0

對這個問題的回答取決於很多事情,例如,在「StringBuilder」中存儲文本的時間有多長等等。要找出的唯一方法是使用內存和/或CPU分析器進行測量。除非創建數十萬個'StringBuilder'對象,否則沒有理由擔心幾個字節。 – Jesper

+1

到目前爲止最大的開銷是IO的成本。除非您不打算將這些數據寫入IO,否則我不會擔心。 –

回答

3

那麼,我最後簡單地測試了一下自己,然後在評論之後再測試一些內容以獲得此編輯答案。

使用JDK 1.7.0_07和測試應用程序報告VM名 「的Java的HotSpot(TM)64位服務器VM」,StringBuilder存儲器使用的粒度是4個字符,在甚至4個字符增加。

答案:從內存分配的角度來看,至少在這個64位JVM上,StringBuilder的任何倍數都是同等優秀的4

通過創建具有不同初始容量的1000000個StringBuilder對象,在不同的測試程序執行中(具有相同的初始堆狀態)以及在前後打印出ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed()進行測試。

打印出的堆大小也得到確認,每個StringBuilder的緩衝區實際從堆中分配的數量是8個字節的偶數倍,正如預期的那樣,因爲Java字符長度爲2個字節。換句話說,分配具有初始容量1..4的1000000個實例需要大約8兆字節的內存(每個實例8個字節),而不是分配相同數量的初始容量爲5 ... 8的實例。

+0

你介意分享你的測試程序嗎? - 你如何設法以這樣的粒度來確定堆的使用情況? – JimmyB

+0

我沒有代碼,但堆使用率在StringBuilder初始容量中增加了4個單位,然後在3個下一個大小上相同,然後再次跳到4的下一個倍數。 **但**這是4個字符,意思是8個字節,對不對?謝謝你的提問,我明天再試一次來驗證這一點。 – hyde

+0

因此,您觀察到1000000 x 4個字節的堆用量增加了? - 我不敢想象估計[數據結構]將佔用多少字節的Java堆空間,而不是用於任何Java程序中的「char」而不是任何其他值/類型。 - 此外,無論堆的*分配*粒度如何,GC決定將內存釋放回堆的粒度都是未知的,並且會影響任何度量。 - 如果您出於好奇和/或測量給定JVM的某些特性而進行測試,請繼續。 - 否則,...看到我的回答上面:) – JimmyB

4

不要在這種情況下變得聰明。

我目前使用128-16,其中128是一個不錯的回合數,減法是分配開銷。

在Java中,這是基於對JVM內部工作原理的完全任意的假設。 Java不是C.字節對齊等絕對是而不是程序員可以或應該嘗試利用的問題。

如果您知道您的字符串的(可能的)最大長度,則可以將其用於初始大小。除此之外,任何優化嘗試都是徒勞的。

如果你真的知道是大量的StringBuilder S的將圍繞很長的時間(這不太適合記錄的概念),你真的覺得有必要去說服JVM爲了節省一些字節的堆空間,你可以嘗試在字符串完全構建之後使用trimToSize()。但是,再一次,只要你的字符串不會浪費兆字節,你就應該去關注應用程序中的其他問題。