我正在處理的Web應用程序(servlet)中有內存泄漏。我懷疑1個原因,並希望聽到你的想法。可能導致泄漏問題?
我使用hashmaps,hashsets等作爲數據庫(大約20MB數據加載)。這些地圖集每10分鐘重新加載一次。有大量的同時請求。我讀到,GC將一些時間/週期內未收集的對象傳遞給較少檢查或垃圾收集的一代(舊世代和永久世代)。我認爲我對靜態貼圖的使用會導致泄漏問題。你怎麼看 ?
我正在處理的Web應用程序(servlet)中有內存泄漏。我懷疑1個原因,並希望聽到你的想法。可能導致泄漏問題?
我使用hashmaps,hashsets等作爲數據庫(大約20MB數據加載)。這些地圖集每10分鐘重新加載一次。有大量的同時請求。我讀到,GC將一些時間/週期內未收集的對象傳遞給較少檢查或垃圾收集的一代(舊世代和永久世代)。我認爲我對靜態貼圖的使用會導致泄漏問題。你怎麼看 ?
如果您刪除了對它的所有引用,則不是泄漏。如果你完全清理你的地圖,那麼它不是泄漏的來源。你應該考慮一下這樣一個事實,即JVM不經常選擇GC終身代,這與你無關 - 重要的是你沒有對它的引用,所以如果它願意的話,JVM可以使用它。
JVM可以用來管理GC有不同的策略,所以我在這裏只是泛泛而不是具體,但GCing終身空間往往非常昂貴並且對應用程序有很大的影響,所以JVM選擇一般不會經常這樣做。
如果您正在查看使用的堆空間量,則會在添加並最終收集項目時看到鋸齒圖案。不要擔心鋸齒的頂端在哪裏,要關心底部的位置(以及如何接近可用的最大堆空間量)。
測試它是否真的是泄漏的一種方法是長時間加載測試您的應用程序。如果泄漏,應用程序正在使用的基本內存量將隨着時間的推移而增加(鋸齒的底部)。如果你不這樣做,它將保持不變。如果確實有泄漏,可以使用分析器來幫助您找到它。
靜態地圖是已知的泄漏源。原因是人們放入東西並且不會將其移除。如果每十分鐘您只需清除緩存然後重新加載,那麼您應該沒問題。
我敢打賭,你沒有正確清理它。 GC部分工作正常,我不擔心這是問題。
如果你有一些方法可以回退到真實的數據,如果你的部分緩存是GC編輯的,但隨後需要的話,你也可以考慮使用WeakReference。
正如羅曼指出的,靜態地圖是一個嫌疑犯。如果由於某種原因,你不能定期清理明確的,你可以考慮使用一個WeakHashMap代替,這是
基於哈希表的Map實現與弱密鑰。 WeakHashMap中的條目將在其密鑰不再處於常規使用狀態時自動刪除。更準確地說,給定鍵的映射的存在不會阻止垃圾收集器丟棄該鍵,也就是說,該鍵被終止,完成並且然後被回收。當一個鍵被丟棄時,它的入口被有效地從地圖上移除,所以這個類的行爲與其他Map實現有所不同。
不幸的是,從Java6開始,標準庫中似乎沒有WeakHashSet,但是可以在網上找到幾個實現。
我建議您使用堆轉儲和堆分析器(如JVisualVM)檢查堆內容。這將幫助您找到泄漏嫌疑人。老一代收集較少的事實並不意味着更多的記憶力正在流失;請記住,雖然它看起來很飽滿,但其中只有一部分代表實況對象,另一部分則由下一個主要的GC進行澄清。像其他人說的那樣,問題可能是由於靜態收集的清理不完全。
永久代不會接收升級對象。它是爲其他目的而保留的一個堆外區域,例如加載類的反射信息和實際字符串。
首先感謝您的答案。我會記住你的建議。 這裏有一些更多的細節; 每隔十分鐘我會按照以下步驟操作 1)我在後臺創建新的地圖(作爲臨時地圖)。 2)使用.clear()方法清除舊地圖(甚至在進入步驟3之前將其分配爲空) 3)爲舊地圖提供新地圖的參考。 我可以在這裏錯過什麼嗎? – WorM 2010-07-21 14:49:43
訪問這些地圖的代碼元素是如何訪問內容的?你確定代碼中沒有其他元素抓取對靜態Map本身的引用嗎?如果設計不好,將數據應用程序廣泛存儲在靜態變量中有點代碼味道,可能會非常簡單地導致泄漏問題。 – 2010-07-21 15:06:53