[英]Does Immutability of Strings in Java cause Out Of Memory
我編寫了一個簡單的Java程序,它從數據庫中讀取了一百萬行並將它們寫入文件。
該程序可以使用的最大內存為512M。
我經常注意到這個程序運行Out Of Memory超過500K行。
由於程序是一個非常簡單的程序,因此很容易發現它沒有內存泄漏。 程序的工作方式是從數據庫中獲取一千行,使用Streams將它們寫入文件,然后獲取下一千行。 每行的大小各不相同,但沒有一行是巨大的。 在程序運行時進行轉儲時,可以在堆上輕松看到舊字符串。 堆中的這些String無法訪問,這意味着他們正在等待收集垃圾。 我也相信GC在執行這個程序時不一定會運行,這會使String在堆中的時間超出它們應該的時間。
我認為解決方案是使用長Char Arrays(或Stringbuffer)而不是使用String對象來存儲DB返回的行。 假設我可以覆蓋Char數組的內容,這意味着可以在多次迭代中使用相同的Char數組,而無需每次都分配新的空間。
偽代碼:
如果上面的偽代碼修復了我的問題,那么實際上String類的不可變特性會傷害Java程序員,因為即使字符串不再使用,也沒有直接的方法來聲明字符串占用的空間。
有沒有更好的替代方案來解決這個問題?
PS:我沒有單獨進行靜態分析。 我使用yourkit profiler來測試堆轉儲。 轉儲顯然說96%的字符串沒有GC根,這意味着他們正在等待收集垃圾。 我也不在我的代碼中使用Substring。
類String
不可變性與OutOfMemoryError
完全無關。 不變性意味着它永遠不會改變,只有那樣。
如果內存不足,那只是因為垃圾收集器無法找到任何要收集的 垃圾 。
在實踐中,很可能你在內存中持有太多字符串的引用(例如,你是否有任何類型的字符串集合,例如List,Set,Map?)。 您必須銷毀這些引用以允許垃圾收集器完成其工作並釋放一些內存。
這個問題的簡單答案是'不'。 我懷疑你的參考時間比你想象的要長。
你正確關閉這些流嗎? 你是intern()
那些字符串。 如果字符串已經存在,那將導致永久復制由字符串組成,並占用permgen空間(未收集)。 你正在使用更大字符串的substring()
嗎? 字符串使用flyweight模式,如果使用substring()
創建,將共享一個字符數組。 有關詳細信息,請參見此處
您建議垃圾收集未運行。 選項-verbose:gc
將記錄垃圾收集,您可以立即看到正在發生的事情。
關於可能導致OutOfMemoryError的字符串的唯一問題是,如果保留更大字符串的小部分。 如果你這樣做,它應該從堆轉儲中顯而易見。
當您進行堆轉儲時,我建議您只查看活動對象,在這種情況下,您不需要的任何保留對象最有可能是代碼中的錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.