Java中是否存在內存泄露問題

什麼是內存泄露:

內存泄露是指一個不再被程序使用的對象或者變量還存在內存中佔有存儲空間。

Java中內存泄露是什麼樣子的:

在C/C++語言中,內存的分配與釋放是由開發人員來負責的,如果開發人員忘記釋放分配的內存就會造成內存泄露。
而在java語言中引進了垃圾回收機制,有垃圾回收器負責回收垃圾,那麼是否還會存在內存泄露問題呢?
其實,在java語言中,判斷一個內存空間是否符合垃圾回收的標準有兩個:
第一:給對象賦予了空值null,以後再沒有被使用過;
第二:給對象賦予了新值,重新分配了內存空間。
一般來講,內存泄露主要有兩種情況:一是在堆中申請的空間沒有被釋放;二是對象已不再被使用,但仍然還在內存中保留着。垃圾回收機制的引入可以有效地解決第一種情況;而對於第二種情況,垃圾回收機制則無法保證不再使用地對象被釋放。因此,Java語言中的內存泄露主要指的是第二種情況。
下面我們通過一段程序來說明一下Java語言中的內存泄露。

Vector v=new Vector(10);
for(int i=1;i<10;i++){
Object o=new Object();
v.add(o);
}

在上述例子的循環中,不斷創建新的對象加到Vector對象中,當退出循環後,o的作用域將會結束,但是由於v在使用這些對象,因此垃圾回收器無法將其回收,此時就造成了內存泄露。只有將這些對象從vector中刪除才能釋放這些對象。

引起內存的原因

在java語言中,容易引起內存泄露的原因很多,主要有以下幾個方面的內容:
**1):靜態集合類:**例如HashMap和Vector。如果這些容器爲靜態的,由於它們的生命週期與程序一致,那麼容器中的對象在程序結束之前將不能被釋放,從而造成內存泄露,如上例所示。
**2)各種鏈接:**例如數據庫鏈接、網絡連接以及IO鏈接等。在對數據庫進行操作的過程中,首先需要建立與數據庫的連接,當不再使用時,需要調用close方法來釋放與數據庫的連接。只有連接被關閉後,垃圾回收器纔會回收對應的對象。否則,如果在訪問數據庫的過程中,對Connection、Statement或ResultSet不顯示的關閉,將會造成大量的對象無法被回收,從而引起內存泄露。
**3)監聽器:**在java語言中,往往會使用到監視器。通常一個應用中會用到很多個監聽器,但在釋放對象的同時往往沒有相應地刪除監聽器,這也可能導致我們的內存泄露。
**4)變量不合理的作用域:**一般而言,如果一個變量定義的作用範圍大於其適用範圍,很有可能會造成內存泄露,另一方面如果沒有及時的把對象設置爲null,很有可能會導致內存泄露,示例如下:

class Server{
private String msg;
public void recueveMsg(){
readFromNet();//把從網絡中接收到的數據保存到msg中
saveDB();//把msg保存到數據庫中
}
}

在上述僞代碼中,通過readFromNet()方法接收的消息保存在變量msg中,然後調用saveDB()方法把msg的內容保存到數據庫中,此時msg已經沒有用了,但是由於msg的生命週期與對象的生命週期相同,此時msg還不能被回收,因此造成內存泄露。對於這個問題,有如下兩種解決方法:
第一種方法,由於msg的作用範圍值在recieveMsg()方法內,因此可以把msg定義爲這個方法的局部變量,當方法結束後,msg的生命週期就會結束,此時垃圾回收器就可以回收msg的內容了;
第二種方法:在使用完msg後就把msg設置爲null,這樣垃圾回收器也會自動回收msg內容所佔的內存空間。
**5)單例模式可能會造成內存泄露:**單例模式的實現方法有很多種,下例中所使用的單例模式就會造成內存泄露:

class BigClass{
class body
}
calss Singleton{
private BigClass be;
private static Singleton instance=new Singleton(new BigClass());
private Singleton(BigClass be){
this.be=be;
}
public Singleton getInstance(){
return instance;
}
}

在上述實現的單例模式中,Singleton存在一個對對象BigClass的引用,由於單利對象以靜態變量的方式存儲,因此它的JVM的整個生命週期都存在,同時由於它有一個對對象BigClass的引用,這樣會導致BigClass類的對象不能夠被回收。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章