Java記憶體泄露問題分析

來源:互聯網
上載者:User
Java記憶體泄露問題分析
  作者:csdn   來源:csdn
很多人在談論記憶體泄露問題,當然對於c/c++來說,這個應該是老掉牙的問題,但是很多Java人員也越來越多得討論這個問題,我這裡寫個小結,希望對大家有一定的參考價值。  記憶體流失的慨念  1.c/c++是程式員自己管理記憶體,Java記憶體是由GC自動回收的。  我雖然不是很熟悉C++,不過這個應該沒有犯常識性錯誤吧。  2.什麼是記憶體泄露?  記憶體泄露是指系統中存在無法回收的記憶體,有時候會造成記憶體不足或系統崩潰。  在C/C++中分配了記憶體不釋放的情況就是記憶體泄露。  3.Java存在記憶體泄露  我們必須先承認這個,才可以接著討論。雖然Java存在記憶體泄露,但是基本上不用很關心它,特別是那些對代碼本身就不講究的就更不要去關心這個了。  Java中的記憶體泄露當然是指:存在無用但是記憶體回收行程無法回收的對象。而且即使有記憶體泄露問題存在,也不一定會表現出來。  4.Java中參數都是傳值的。  對於基本類型,大家基本上沒有異議,但是對於參考型別我們也不能有異議。  Java記憶體泄露情況  JVM回收演算法是很複雜的,我也不知道他們怎麼實現的,但是我只知道他們要實現的就是:對於沒有被引用的對象是可以回收的。所以你要造成記憶體泄露就要做到:  持有對無用對象的引用!  不要以為這個很容易做到,既然無用,你怎麼還會持有它的引用? 既然你還持有它,它怎麼會是無用的呢?  我實在想不到比那個堆棧更經典的例子了,以致於我還要引用別人的例子,下面的例子不是我想到的,是書上看到的,當然如果沒有在書上看到,可能過一段時間我自己也想的到,可是那時我說是我自己想到的也沒有人相信的。public class Stack {
 private Object[] elements=new Object[10];
 private int size = 0; public void push(Object e){
  ensureCapacity();
  elements[size++] = e;
 } public Object pop(){
  if( size == 0)
   throw new EmptyStackException();
   return elements[--size];
 }private void ensureCapacity(){
 if(elements.length == size){
  Object[] oldElements = elements;
  elements = new Object[2 * elements.length+1];
  System.arraycopy(oldElements,0, elements, 0, size);
 }
}
}   上面的原理應該很簡單,假如堆棧加了10個元素,然後全部彈出來,雖然堆棧是空的,沒有我們要的東西,但是這是個對象是無法回收的,這個才符合了記憶體泄露的兩個條件:無用,無法回收。  但是就是存在這樣的東西也不一定會導致什麼樣的後果,如果這個堆棧用的比較少,也就浪費了幾個K記憶體而已,反正我們的記憶體都上G了,哪裡會有什麼影響,再說這個東西很快就會被回收的,有什麼關係。下面看兩個例子。  例子1public class Bad{
 public static Stack s=Stack();
  static{
   s.push(new Object());
   s.pop(); //這裡有一個對象發生記憶體泄露
   s.push(new Object()); //上面的對象可以被回收了,等於是自愈了
  }
}   因為是static,就一直存在到程式退出,但是我們也可以看到它有自愈功能,就是說如果你的Stack最多有100個對象,那麼最多也就只有100個對象無法被回收其實這個應該很容易理解,Stack內部持有100個引用,最壞的情況就是他們都是無用的,因為我們一旦放新的進取,以前的引用自然消失!  例子2public class NotTooBad{
 public void doSomething(){
  Stack s=new Stack();
  s.push(new Object());
  //other code
  s.pop();//這裡同樣導致對象無法回收,記憶體泄露.
 }//退出方法,s自動無效,s可以被回收,Stack內部的引用自然沒了,所以
 //這裡也可以自愈,而且可以說這個方法不存在記憶體泄露問題,不過是晚一點
 //交給GC而已,因為它是封閉的,對外不開放,可以說上面的代碼99.9999%的
 //情況是不會造成任何影響的,當然你寫這樣的代碼不會有什麼壞的影響,但是
 //絕對可以說是垃圾代碼!沒有矛盾吧,我在裡面加一個空的for迴圈也不會有
 //什麼太大的影響吧,你會這麼做嗎?
}   上面兩個例子都不過是小打小鬧,但是C/C++中的記憶體泄露就不是Bad了,而是Worst了。他們如果一處沒有回收就永遠無法回收,頻繁的調用這個方法記憶體不就用光了!因為Java還有自愈功能(我自己起的名字,還沒申請專利),所以Java的記憶體泄露問題幾乎可以忽略了,但是知道的人就不要犯了。  不知者無罪!Java存在記憶體泄露,但是也不要誇大其辭。如果你對Java都不是很熟,你根本就不用關心這個,我說過你無意中寫出記憶體泄露的例子就像你中一千萬一樣機率小,開玩笑了,其實應該是小的多的多!  而且即使你有幸寫出這樣的代碼,中獎了!基本上都是一包洗衣粉,不會讓你發財,對系統沒有什麼大的影響。  杞人憂天的情況  1.無話可說型Object obj=new Object();
obj=null;
//這個完全多此一舉,因為退出了作用範圍,對象的引用自動消失
//不要在你的程式中出現這樣的語句,沒有錯,但是就是不雅觀   2.思考不對型void func(Object o){
 o=new Object();
 return
}   當我們知道Java參數是傳值,就知道上面的方法什麼也沒錯,就是申請了一個對象然後再丟給GC。因為是傳值,這裡的o是一個調用時候的拷貝,會不會無法回收?不就是拷貝嗎,退出方法什麼都沒了,這個對象怎麼會留的住。  3.盡量避免型class A{
 B b=new B(this);
}
class B{
 A a;
 B(A a){this.a=a;}
}   這個存在互相引用,可能導致孤島現象,但是這個不會造成記憶體泄露不過我自己覺得這個會降低GC的效率,就從我的智力來看,我覺得這種情況比一般情況難以判斷怎麼回收!當然GC比我聰明,不過應該也要動一點腦子吧。
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.