簡體   English   中英

Java String對象沒有按時收集垃圾

[英]Java String objects not getting garbage collected on time

我有一個有趣的Java內存消耗問題。 我有一個本機C ++應用程序,它調用我的Java應用程序。

應用程序基本上做了一些語言翻譯\\解析一些XML並響應網絡請求。 大多數應用程序的狀態不必保留,因此它充滿了接受String參數並返回字符串結果的Methods。

隨着時間的推移,這個應用程序繼續占用越來越多的內存,並且有一段時間它開始占用接近2 GB的內存,這使我們懷疑某些Hashtable或靜態變量中存在泄漏。 經過仔細檢查,我們沒有發現任何泄漏。 比較一段時間內的堆轉儲,顯示char []和String對象占用大量內存。

然而,當我們檢查這些char []時,我們發現它們沒有GC根,這意味着它們不應該是泄漏的原因。 由於它們是堆的一部分,這意味着它們正在等待垃圾收集。 在使用了很好的工具MAT \\ VisualVM \\ JHat並滾動瀏覽了很多這樣的對象后,我使用了yourkit的試用版。 Yourkit直接提供數據,表示96%的char []和String無法訪問。 這意味着在進行轉儲時,堆中96%的字符串正在等待垃圾收集。

我知道GC運行很少但是當你通過VisualVM檢查時,你實際上可以看到它正在運行:-(而不是為什么堆上有這么多未使用的對象。

IMO這個應用程序永遠不應該超過400-500 MB內存,這是它在前24小時停留的地方,但它繼續增加堆:-(

我正在運行Java 1.6.0-25。

請注意yourkit的截圖

謝謝你的幫助。

當你認為它/它應該是Java時,它不是GC :-) GC是一個太復雜的主題,無法花費幾周的時間來理解正在發生的事情,真正深入研究細節。 因此,如果你看到你無法解釋的行為,那並不意味着它被打破了。

你看到的可能有幾個原因:

  1. 您正在將一個巨大的String加載到內存中並保留對子字符串的引用。 這可以將整個字符串保留在內存中(Java並不總是為子字符串分配新的char數組 - 因為字符串是不可變的,它只是重用原始的char數組並記住偏移量和長度)。

  2. 到目前為止,沒有任何事情觸發GC。 一些C ++開發人員認為GC是“邪惡的”(任何你不理解的東西都必須是邪惡的,對嗎?)因此他們將Java配置為不運行它,除非絕對必要。 這意味着VM將占用內存,直到它達到最大值,然后,它將執行一次巨大的GC運行。

  3. build 25已經很老了。 嘗試更新到最新的Java版本(33,我認為)。 GC是VM中經過最佳測試的部分之一,但它確實存在錯誤。 也許你打了一個。

  4. 除非您看到OutOfMemoryException,否則您沒有泄漏。 我們有一個應用程序可以吃掉你給它的所有堆。 如果它有16GB的RAM(“只是為了安全”),它將使用整個16GB,因為我們可以緩存。 你永遠不會看到內存不足,因為緩存會根據需要縮小,但系統管理員經常會驚慌失措 “哦天啊!天哪!它的內存耗盡PANIK不,它不是。 除非Java告訴你,否則它不會耗盡內存。 它只是有效地使用它。

  5. 使用命令行選項調整GC是打破它的最佳方法之一。 數以百計的人對這個話題的了解比以往任何時候都要多,他們會花費數年時間來提高GC的效率。 你認為你可以做得更好嗎? 祝好運。 - >擺脫任何“魔術”命令行選項並調用System.gc() ,你的問題可能會消失。

嘗試將堆大小減小到500兆字節,看看軟件是否會開始垃圾收集或死亡。 Java對於使用給它的內存來說並不是太挑剔。 您也可以研究GC調整選項,這將使GC更清楚地清理東西。

String reallyLongString = "this is a really long String";
String tinyString = reallyLongString.substring(2, 3);
reallyLongString = null

在上面的例子中,JVM無法收集為長字符串分配的內存,因為它有部分引用。 如果你正在使用Strings,你會遇到記憶問題,這可能是你悲傷的原因。

使用tinyString = new String(reallyLongString.substring(2, 3);相反。

可能根本沒有泄漏 - 如果String可以訪問則會發生泄漏。 如果你已經為應用程序分配了多達2GB的內容,那么垃圾收集器就沒有理由在你接近該限制之前開始釋放內存。 如果您不希望它占用超過500MB,則在啟動JVM時傳遞-Xmx 512m

您也可以嘗試調整垃圾收集器以便更早地開始清理。

首先,不要再擔心那些Strings和char []了。 在我所描述的幾乎所有Java應用程序中,它們都位於內存使用者列表的頂部。 幾乎沒有那些Java應用程序,他們是真正的問題。

如果你還沒有收到OutOfMemoryError,但是擔心2GB對你的java進程來說太多了,那么試着減少傳遞給它的Xmx值。 如果運行良好且512m或1g好,那問題就解決了,不是嗎?

如果你得到OOM,那么你可以嘗試的另一個選擇是在你的java進程中使用Plumbr 它是內存泄漏發現工具,如果確實存在內存泄漏,它可以幫助您。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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