1. 程式人生 > >記憶體洩漏小例子

記憶體洩漏小例子

陣列

 public Object pop(){   
    if(size==0) throw new EmptyStackException();   
    return element[--size]; //短暫造成記憶體洩露   
    }  

上面的程式碼每一次pop()的時候,Stack都會彈出一個元素,在沒有加入新元素之前,實際上仍然有一個引用element[x]指向了這個已經 彈出的物件,因此GC是不會對其進行垃圾回收的。只有push()新元素的時候使得element[x]=newObject,才會使得以前建立的物件有 可能被回收。應該把上面的pop()方法改成下面的程式碼就安全多了:
public Object pop(){    
       if(element.length==size) throws EmptyStackException();    
       Object o=element[--size];    
       elements[size]=null;  //使得GC有機會回收這個物件     
       return o;    
}

    

靜態集合類

在使用Set、Vector、HashMap等集合類的時候需要特別注意,有可能會發生記憶體洩漏。當這些集合被定義成靜態的時候,由於它們的生命週期跟應用程式一樣長,這時候,就有可能會發生記憶體洩漏,看下面程式碼:
class StaticTest
{
    private static Vector v = new Vector(10);


    public void init()
    {
        for (int i = 1; i < 100; i++)
        {
            Object object = new Object();
            v.add(object);
            object = null;
        }
    }
}


在上面的程式碼中,迴圈申請了Object物件,並新增到Vector中,然後將物件設定為null,可是這些物件因為被Vector引用著,因此並不能被GC回收,因此造成了記憶體洩漏。因此,要釋放這些物件,還需要被它們從Vector刪除,最簡單的方法就是將Vector設定為null。


集合裡的物件屬性值被改變,看以下程式碼:
public static void main(String[] args)
{
    Set<Student> set = new HashSet<Student>();
    Student s1 = new Student("Jack");
    Student s2 = new Student("Mary");
    Student s3 = new Student("Eason");


    set.add(s1);
    set.add(s2);
    set.add(s3);


    System.out.println(set.size());//3
    s2.setName("Jackson"); //修改屬性,此時s2元素對應的hashcode值發生改變
    set.remove(s2);        // remove不掉,造成記憶體洩漏
    set.add(s2);           // 新增成功


    System.out.println(set.size());//4
}
在這個例子中,由於物件s2的屬性值被改變了,因此不能從set中刪除,所以set中會一直保持著s2的引用,不能被回收,造成了記憶體洩漏。


監聽器

在Java中,我們經常會使用到監聽器,如對某個控制元件新增單擊監聽器addOnClickListener(),但往往釋放物件的時候會忘記刪除監聽器,這就有可能造成記憶體洩漏。好的方法就是,在釋放物件的時候,應該記住釋放所有監聽器,這就能避免了因為監聽器而導致的記憶體洩漏。


各種連線

Java中的連線包括資料庫連線、網路連線和io連線,如果沒有顯式呼叫其close()方法,是不會自動關閉的,這些連線就不能被GC回收而導致記憶體洩漏。一般情況下,在try程式碼塊裡建立連線,在finally裡釋放連線,就能夠避免此類記憶體洩漏。


外部模組的引用

呼叫外部模組的時候,也應該注意防止記憶體洩漏。如模組A呼叫了外部模組B的一個方法,如:
public void register(Object o)
這個方法有可能就使得A模組持有傳入物件的引用,這時候需要檢視B模組是否提供了去除引用的方法,如unregister()。這種情況容易忽略,而且發生了記憶體洩漏的話,比較難察覺,應該在編寫程式碼過程中就應該注意此類問題。


單例模式

使用單例模式的時候也有可能導致記憶體洩漏。因為單例物件初始化後將在JVM的整個生命週期記憶體在,如果它持有一個外部物件(生命週期比較短)的引用,那麼這個外部物件就不能被回收,而導致記憶體洩漏。如果這個外部物件還持有其它物件的引用,那麼記憶體洩漏會更嚴重,因此需要特別注意此類情況。這種情況就需要考慮下單例模式的設計會不會有問題,應該怎樣保證不會產生記憶體洩漏問題。