1.靜態集合類
聲明為靜態(static)的HashMap、Vector 等集合類的使用最容易引起內存泄漏,因為這些靜態變量的生命周期與應用程序一致,如示例1,如果該Vector 是靜態的,那么它將一直存在,而其中所有的Object對象也不能被釋放,因為它們也將一直被該Vector 引用着。
2. 監聽器
在java 編程中,我們都需要和監聽器打交道,通常一個應用當中會用到很多監聽器,我們會調用一個控件的諸如addXXXListener()等方法來增加監聽器,但往往在釋放對象的時候卻沒有記住去刪除這些監聽器,從而增加了內存泄漏的機會。
3. 物理連接
一些物理連接,比如數據庫連接和網絡連接,除非其顯式的關閉了連接,否則是不會自動被GC 回收的。例如Java 數據庫連接一般用DataSource.getConnection()來創建,當不再使用時必須用Close()方法來釋放,因為這些連接是獨立於JVM的。其中對於Resultset和Statement對象可以不進行顯式回收,但Connection一定要顯式回收,因為Connection在任何時候都無法自動回收,而Connection一旦回收,Resultset和Statement對象就會立即為NULL。但是如果使用連接池,情況就不一樣了,除了要顯式地關閉連接,還必須顯式地關閉Resultset和Statement對象(關閉其中一個,另外一個也會關閉),否則就會造成大量的Statement 對象無法釋放,從而引起內存泄漏。
4. 內部類和外部模塊等的引用
內部類的引用是比較容易遺忘的一種,而且一旦沒釋放可能導致一系列的后繼類對象沒有釋放。對於程序員而言,自己的程序很清楚,如果發現內存泄漏,自己對這些對象的引用可以很快定位並解決,但是現在的實際開發過程中往往並非一個人實現,模塊化的思想在現代軟件中非常明顯,所以程序員要小心外部模塊不經意的引用,例如程序員A 負責A 模塊,調用了B 模塊的一個方法如:
public void registerMsg(Object b);
這種調用就要非常小心了,傳入了一個對象,很可能模塊B就保持了對該對象的引用,這時候就需要注意模塊B 是否提供相應的操作去除引用。