簡體   English   中英

Java中字符串的不變性是否會導致內存不足

[英]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數組,而無需每次都分配新的空間。

偽代碼:

  1. 使用new char [1000] [1000]創建一個數組數組;
  2. 從DB填充數千行。
  3. 將數組寫入文件。
  4. 對下一千行使用相同的數組

如果上面的偽代碼修復了我的問題,那么實際上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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM