高效Java第六條消除過期的物件引用無意識的物件保持
問題的引出

這段程式有一個“記憶體洩露”,隨著GC活動的增加,或者由於記憶體佔用的不斷增加,程式效能降低會逐漸表現出來。在極端的情況下,這種記憶體洩露會導致磁碟交換,甚至導致程式失敗(OutOfMemoryError),但是這種失敗情況相對比較少見。
記憶體洩露的地方:一個棧先是增長,然後再收縮,那麼,從棧中彈出來的物件將不會被當做垃圾回收,即使使用棧的程式不再引用這些物件,它們也不會被回收。
棧內部維護著對這些物件的過期引用(永遠也不會再被解除的引用)。
elements陣列中下標小於size的那些元素都是過期的。
無意識的物件保持導致的問題
在支援垃圾回收的語言中,記憶體洩露是很隱蔽的,無意識的物件保持。
一個物件引用被無意識地保留起來,那麼,GC不僅不會處理這個物件,而且也不會處理這個物件所引用的所有其他物件,因此有可能會對效能造成潛在的重大影響。
無意識的物件保持修復方法
一旦物件引用已經過期,只需清空這些引用即可。

清空過期引用的另一個好處是,如果它們以後又被錯誤地解除引用,程式會立即丟擲NullPointerException異常,而不是悄悄地錯誤執行下去。
清空物件引用應該是一種例外,而不是一種規範行為
清除過期引用最好的辦法是讓包含該引用的變數結束其生命週期。
清空引用的時機
Stack類自己管理記憶體。儲存池包含了elements陣列的元素。陣列活動區域中的元素是已分配的,而陣列其餘部分的元素則是自由的。但是GC並不知道這一點;對於GC而言,elements陣列中的所有物件引用都同等有效。只有程式設計師知道陣列的非活動部分是不重要的。程式設計師可以把這個情況告知GC:一旦陣列元素變成了非活動部分的一部分,程式設計師就手工清空這些陣列元素。
只要類是自己管理記憶體,程式設計師就應該警惕記憶體洩露問題。一旦元素被釋放掉,則該元素中包含的任何物件引用都應該被清空。
記憶體洩露的另一個常見來源是快取
只要在快取之外存在對某個項的鍵的引用,該項就有意義,那麼就可以用WeakHashMap代表快取;當快取中的項過期之後,它們就會自動被刪除。記住只有當所要的快取項的生命週期是由該鍵的外部引用而不是由值決定時,才有用處。
"快取項的生命週期是否有意義"並不是很容易確定,隨著時間的推移,其中的項會變得越來越沒有價值。在這種情況下,快取應該時不時地清理掉沒用的項。這項清除工作可以由一個後臺執行緒來完成,或在給快取新增新條目的時候順便進行清理。
LinkedHashMap類可以使用removeEldestEntry()實現在給快取新增新條目的時候進行清理。
對於更復雜的快取,必須直接使用java.lang.ref。
記憶體洩露的第三個常見的來源是監聽器和其他回撥。
客戶端在API中註冊回撥,卻沒有顯示地取消註冊。
確保回撥立即被當做垃圾回收的最佳方法是隻儲存它們的弱引用,例如,只將它們儲存成中的鍵。
為了讓學習變得輕鬆、高效,今天給大家免費分享一套Java教學資源。幫助大家在成為Java架構師的道路上披荊斬棘。需要資料的歡迎加入學習交流群:9285,05736