<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-144  評論-80  文章-1  trackbacks-0
    很多人在談論內存泄露問題,當然對于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了,哪里會有什么影響,再說這個東西很快就會被回收的,有什么關系。下面看兩個例子。

      例子1

    public class Bad{
     public static Stack s=Stack();
      static{
       s.push(new Object());
       s.pop(); //這里有一個對象發生內存泄露
       s.push(new Object()); //上面的對象可以被回收了,等于是自愈了
      }
    }

      因為是static,就一直存在到程序退出,但是我們也可以看到它有自愈功能,就是說如果你的Stack最多有100個對象,那么最多也就只有100個對象無法被回收其實這個應該很容易理解,Stack內部持有100個引用,最壞的情況就是他們都是無用的,因為我們一旦放新的進取,以前的引用自然消失!

      例子2

    public 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比我聰明,不過應該也要動一點腦子吧。
    posted on 2005-03-11 09:35 小力力力 閱讀(245) 評論(0)  編輯  收藏 所屬分類: JAVA
    主站蜘蛛池模板: 免费福利电影在线观看| 狠狠热精品免费观看| 成人A毛片免费观看网站| 看全色黄大色大片免费久久| 最近免费中文字幕大全视频| 亚洲精品综合久久中文字幕| 国产精品99久久免费观看| 国产精品亚洲а∨无码播放| 国产免费区在线观看十分钟| 亚洲色欲色欲www在线丝| 免费激情网站国产高清第一页| 免费在线黄色网址| 免费无毒a网站在线观看| 亚洲性久久久影院| 亚洲天堂在线播放| 一级毛片在线免费观看| 久久精品国产亚洲AV嫖农村妇女| 4399影视免费观看高清直播| 亚洲第一页在线播放| 国产免费久久精品99re丫y| 亚洲国产精华液2020| 免费v片在线观看品善网| 成人av片无码免费天天看| 亚洲国产天堂久久综合网站| 国产又大又粗又长免费视频| 亚洲日韩av无码中文| 国内精品免费在线观看| 97se亚洲综合在线| 精品熟女少妇AV免费观看| 国产成人亚洲综合a∨| 国产亚洲欧洲精品| 免费成人福利视频| 麻豆亚洲AV成人无码久久精品 | 亚洲女人影院想要爱| 一色屋成人免费精品网站| 国产午夜亚洲精品不卡电影| 亚洲成在人线av| 在线看片无码永久免费视频| 曰批免费视频播放在线看片二| 水蜜桃亚洲一二三四在线| 免费黄色app网站|