1. 程式人生 > >Java中會存在記憶體洩露嗎,請簡單描述。

Java中會存在記憶體洩露嗎,請簡單描述。

會。java導致記憶體洩露的原因很明確:長生命週期的物件持有短生命週期物件的引用就很可能發生記憶體洩露,儘管短生命週期物件已經不再需要,但是因為長生命週期物件持有它的引用而導致不能被回收,這就是java中記憶體洩露的發生場景。

1.集合類,集合類僅僅有新增元素的方法,而沒有相應的刪除機制,導致記憶體被佔用。這一點其實也不明確,這個集合類如果僅僅是區域性變數,根本不會造成記憶體洩露,在方法棧退出後就沒有引用了會被jvm正常回收。而如果這個集合類是全域性性的變數(比如類中的靜態屬性,全域性性的map等即有靜態引用或final一直指向它),那麼沒有相應的刪除機制,很可能導致集合所佔用的記憶體只增不減,因此提供這樣的刪除機制或者定期清除策略非常必要。

2.單例模式。不正確使用單例模式是引起記憶體洩露的一個常見問題,單例物件在被初始化後將在JVM的整個生命週期中存在(以靜態變數的方式),如果單例物件持有外部物件的引用,那麼這個外部物件將不能被jvm正常回收,導致記憶體洩露,考慮下面的例子:

class A{

public A(){

B.getInstance().setA(this);

}

....

}

//B類採用單例模式

class B{

private A a;

private static B instance=new B();

public B(){}

public static B getInstance(){

return instance;

}

public void setA(A a){

this.a=a;

}

//getter...

}

  顯然B採用singleton模式,他持有一個A物件的引用,而這個A類的物件將不能被回收。想象下如果A是個比較大的物件或者集合型別會發生什麼情況。

  補充:3.當一個物件被儲存進HashSet集合中以後,就不能修改這個物件中的哪些參與計算雜湊值的欄位了,否則,物件修改後的雜湊值與最初儲存進HashSet集合中的雜湊值就不同了,在這種情況下,即使在contains()方法使用該物件的當前引用作為的引數HashSet集合中檢索物件,也將返回找不到物件的結果,這也會導致無法從HashSet集合中單獨刪除當前物件,造成記憶體洩露。

   下面給出了一個簡單的記憶體洩露的例子。在這個例子中,我們迴圈申請Object物件,並將所申請的物件放入一個Vector中,如果我們僅僅釋放引用本身,那麼Vector仍然引用該物件,所以這個物件對GC來說是不可回收的。因此,如果物件加入到Vector後,還必須從Vector中刪除,最簡單的方法就是將Vector物件設定為null。

public class MemoryLeak {
	public static void main(String[] args) {
		Vector v = new Vector(10);
		for(int i = 0; i < 100; i++) {
			Object o = new Object();
			v.add(o);
			o=null;
		}
	}
}

//此時,所有的Object物件都沒有被釋放,因為變數v引用這些物件。

上面所講的這些也啟發我們如何去查詢記憶體洩露問題,在程式碼複審的時候關注長生命週期物件:全域性性的集合、單例模式的使用、類的static變數等等Java的實現過程中,也要考慮其物件釋放,最好的方法是在不使用某物件時,顯式地將此物件賦空。最好遵循誰建立誰釋放的原則。