天天看點

記憶體洩露(Memory Leaks)簡介1. 什麼是記憶體洩露?2. 為什麼會發生記憶體洩露?3. 如何防止記憶體洩露?4. 小測驗:為什麼JDK6中的substring()方法會引起記憶體洩露?

    Java最大的一個優勢是它的記憶體管理。你可以很友善地建立對象,而Java垃圾回收器(Garbage Collector)則會負責配置設定并釋放記憶體。然而,實際情況并非如此簡單,Java應用程式經常會發生記憶體洩露的問題。

    本文介紹了什麼是記憶體洩露、記憶體洩露是如何發生的,以及,如何防止記憶體洩露。

1. 什麼是記憶體洩露?

    記憶體洩露的定義:應用程式已經不再需要使用對象,但由于它們依然被引用,導緻垃圾回收器無法将其移除。

    為了進一步了解這一定義,我們需要知道記憶體中對象的狀态。下圖将會說明什麼是未被使用(unused),什麼是未被引用(unreferenced)。

記憶體洩露(Memory Leaks)簡介1. 什麼是記憶體洩露?2. 為什麼會發生記憶體洩露?3. 如何防止記憶體洩露?4. 小測驗:為什麼JDK6中的substring()方法會引起記憶體洩露?

    上圖中,有被引用的對象(referenced object)和未被引用的對象(unreferenced object)。未被引用的對象會被垃圾回收器回收,而被引用的對象則不會。未被引用的對象肯定是未被使用的,因為其他對象沒有引用它。然而,未被使用的對象不全是未被引用的。未被使用的對象有可能被引用。這就導緻了記憶體洩露。

2. 為什麼會發生記憶體洩露?

    我們來看看下面的例子,研究記憶體洩露是如何發生的。在下面的例子中,對象A引用了對象B。A的生命周期(t1-t4)比B的生命周期(t2-t3)長得多。在應用程式中,如果B已經不再被使用,A卻還保留着對B的引用。這樣,垃圾回收器就無法将B移出記憶體。一旦A保留了大量對不會再被使用的對象的引用,就會導緻大量的對象無法被回收,造成記憶體空間的消耗,這就很可能出現記憶體洩露。

    還有可能是,B也保留了大量對其他對象的引用,導緻這些被B引用的對象也無法被回收。所有這些未被使用的對象都會消耗寶貴的記憶體空間。

記憶體洩露(Memory Leaks)簡介1. 什麼是記憶體洩露?2. 為什麼會發生記憶體洩露?3. 如何防止記憶體洩露?4. 小測驗:為什麼JDK6中的substring()方法會引起記憶體洩露?

3. 如何防止記憶體洩露?

    下面是一些關于記憶體洩露的實踐經驗。

    1. 注意集合(Collection)類,如HashMap、ArrayList等,因為使用這些類的地方經常會出現記憶體洩露。一旦将集合類聲明為靜态(static),那麼它們的生命周期就和應用程式的生命周期一樣長。

    2. 注意事件監聽器和回調方法。如果事件監聽器被注冊,當類不再被使用時,要注意将監聽器取消注冊,否則會出現記憶體洩露。

    3. “如果類管理它自己的記憶體,程式員就特别要注意記憶體洩露的問題。”[1]通常,如果一個對象中的成員變量指向其他的對象,則需要消除這些引用。

4. 小測驗:為什麼JDK6中的substring()方法會引起記憶體洩露?

    在文章Substring() in JDK6和7中給出這個問題的答案。

參考文獻:

[1] Bloch, Joshua. Effective java. Addison-Wesley Professional, 2008.

[2] IBM Developer Work. http://www.ibm.com/developerworks/library/j-leaks/

原文位址:The Introduction of Memory Leaks