Java中的內存泄漏

Java內存回收機制

不論哪種語言的內存分配方式泼返,都需要返回所分配內存的真實地址娜氏,也就是返回一個指針到內存塊的首地址抽活。Java中對象是采用new或者反射的方法創(chuàng)建的子巾,這些對象的創(chuàng)建都是在堆(Heap)中分配的,所有對象的回收都是由Java虛擬機通過垃圾回收機制完成的茶敏。GC為了能夠正確釋放對象壤靶,會監(jiān)控每個對象的運行狀況,對他們的申請惊搏、引用贮乳、被引用、賦值等狀況進行監(jiān)控恬惯,Java會使用有向圖的方法進行管理內存向拆,實時監(jiān)控對象是否可以達到,如果不可到達酪耳,則就將其回收浓恳,這樣也可以消除引用循環(huán)的問題。在Java語言中,判斷一個內存空間是否符合垃圾收集標準有兩個:一個是給對象賦予了空值null颈将,以下再沒有調用過梢夯,另一個是給對象賦予了新值,這樣重新分配了內存空間吆鹤。

Java內存泄漏引起的原因

內存泄漏是指無用對象(不再使用的對象)持續(xù)占有內存或無用對象的內存得不到及時釋放厨疙,從而造成內存空間的浪費稱為內存泄漏洲守。內存泄露有時不嚴重且不易察覺疑务,這樣開發(fā)者就不知道存在內存泄露,但有時也會很嚴重梗醇,會提示你Out of memory知允。
Java內存泄漏的根本原因是什么呢?長生命周期的對象持有短生命周期對象的引用就很可能發(fā)生內存泄漏叙谨,盡管短生命周期對象已經不再需要温鸽,但是因為長生命周期持有它的引用而導致不能被回收,這就是Java中內存泄漏的發(fā)生場景手负。具體主要有如下幾大類:

  • 1涤垫、靜態(tài)集合類引起內存泄漏:
    像HashMap、Vector等的使用最容易出現內存泄露竟终,這些靜態(tài)變量的生命周期和應用程序一致蝠猬,他們所引用的所有的對象Object也不能被釋放,因為他們也將一直被Vector等引用著统捶。例如
    Static Vector v = new Vector(10);
    for (int i = 1; i < 100; i++) {
    Object o = new Object();
    v.add(o);
    o = null;
    }

在這個例子中榆芦,循環(huán)申請Object 對象,并將所申請的對象放入一個Vector 中喘鸟,如果僅僅釋放引用本身(o=null)匆绣,那么Vector 仍然引用該對象,所以這個對象對GC 來說是不可回收的什黑。因此崎淳,如果對象加入到Vector 后,還必須從Vector 中刪除愕把,最簡單的方法就是將Vector對象設置為null凯力。

  • 2、當集合里面的對象屬性被修改后礼华,再調用remove()方法時不起作用咐鹤。例如

    public static void main(String[] args) {
    Set<Person> set = new HashSet<Person>();
    Person p1 = new Person("唐僧", "pwd1", 25);
    Person p2 = new Person("孫悟空", "pwd2", 26);
    Person p3 = new Person("豬八戒", "pwd3", 27);
    set.add(p1);
    set.add(p2);
    set.add(p3);
    System.out.println("總共有:" + set.size() + " 個元素!"); // 結果:總共有:3 個元素!
    p3.setAge(2); // 修改p3的年齡,此時p3元素對應的hashcode值發(fā)生改變

      set.remove(p3); // 此時remove不掉,造成內存泄漏
    
      set.add(p3); // 重新添加圣絮,居然添加成功
      System.out.println("總共有:" + set.size() + " 個元素!"); // 結果:總共有:4 個元素!
      for (Person person : set) {
          System.out.println(person);
      }
    

    }

  • 3祈惶、監(jiān)聽器
    在java 編程中,我們都需要和監(jiān)聽器打交道,通常一個應用當中會用到很多監(jiān)聽器捧请,我們會調用一個控件的諸如addXXXListener()等方法來增加監(jiān)聽器凡涩,但往往在釋放對象的時候卻沒有記住去刪除這些監(jiān)聽器,從而增加了內存泄漏的機會疹蛉。

  • 4活箕、各種連接
    比如數據庫連接(dataSourse.getConnection()),網絡連接(socket)和io連接可款,除非其顯式的調用了其close()方法將其連接關閉育韩,否則是不會自動被GC 回收的。對于Resultset 和Statement 對象可以不進行顯式回收闺鲸,但Connection 一定要顯式回收筋讨,因為Connection 在任何時候都無法自動回收,而Connection一旦回收摸恍,Resultset 和Statement 對象就會立即為NULL悉罕。但是如果使用連接池,情況就不一樣了立镶,除了要顯式地關閉連接壁袄,還必須顯式地關閉Resultset Statement 對象(關閉其中一個,另外一個也會關閉)媚媒,否則就會造成大量的Statement 對象無法釋放嗜逻,從而引起內存泄漏。這種情況下一般都會在try里面去的連接欣范,在finally里面釋放連接变泄。

  • 5、內部類和外部模塊的引用
    內部類的引用是比較容易遺忘的一種恼琼,而且一旦沒釋放可能導致一系列的后繼類對象沒有釋放妨蛹。此外程序員還要小心外部模塊不經意的引用,例如程序員A負責A模塊晴竞,調用了B模塊的一個方法如: public void registerMsg(Object b); 這種調用就要非常小心了蛙卤,傳入了一個對象,很可能模塊B就保持了對該對象的引用噩死,這時候就需要注意模塊B是否提供相應的操作去除引用颤难。

  • 6、單例模式
    不正確使用單例模式是引起內存泄漏的一個常見問題已维,單例對象在初始化后將在JVM的整個生命周期中存在(以靜態(tài)變量的方式)行嗤,如果單例對象持有外部的引用,那么這個對象將不能被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類的對象將不能被回收护奈。


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市哥纫,隨后出現的幾起案子霉旗,更是在濱河造成了極大的恐慌,老刑警劉巖蛀骇,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厌秒,死亡現場離奇詭異,居然都是意外死亡松靡,警方通過查閱死者的電腦和手機简僧,發(fā)現死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門建椰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雕欺,“玉大人,你說我怎么就攤上這事棉姐⊥懒校” “怎么了?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵伞矩,是天一觀的道長笛洛。 經常有香客問我,道長乃坤,這世上最難降的妖魔是什么苛让? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮湿诊,結果婚禮上狱杰,老公的妹妹穿的比我還像新娘。我一直安慰自己厅须,他們只是感情好仿畸,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著朗和,像睡著了一般错沽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上眶拉,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天千埃,我揣著相機與錄音,去河邊找鬼忆植。 笑死放可,一個胖子當著我的面吹牛皿曲,可吹牛的內容都是我干的。 我是一名探鬼主播吴侦,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼屋休,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了备韧?” 一聲冷哼從身側響起劫樟,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎织堂,沒想到半個月后叠艳,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡易阳,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年附较,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片潦俺。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡拒课,死狀恐怖,靈堂內的尸體忽然破棺而出事示,到底是詐尸還是另有隱情早像,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布肖爵,位于F島的核電站卢鹦,受9級特大地震影響,放射性物質發(fā)生泄漏劝堪。R本人自食惡果不足惜冀自,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望秒啦。 院中可真熱鬧熬粗,春花似錦、人聲如沸帝蒿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽葛超。三九已至暴氏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绣张,已是汗流浹背答渔。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留侥涵,地道東北人沼撕。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓宋雏,卻偏偏與公主長得像,于是被迫代替她去往敵國和親务豺。 傳聞我的和親對象是個殘疾皇子磨总,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內容

  • 內存泄漏內存泄漏發(fā)生的原因造成內存泄露的常見情形內存泄露的解決方案 Java的一個最顯著的優(yōu)勢是內存管理。你只需要...
    六尺帳篷閱讀 2,621評論 1 6
  • Android 內存泄漏總結 內存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應用出現內存泄漏的問題笼沥。內存泄漏...
    _痞子閱讀 1,637評論 0 8
  • 1. Java基礎部分 基礎部分的順序:基本語法蚪燕,類相關的語法,內部類的語法奔浅,繼承相關的語法馆纳,異常的語法,線程的語...
    子非魚_t_閱讀 31,657評論 18 399
  • (一)Java部分 1汹桦、列舉出JAVA中6個比較常用的包【天威誠信面試題】 【參考答案】 java.lang;ja...
    獨云閱讀 7,114評論 0 62
  • 在外流浪了一年多鲁驶,因為割舍不下家人,趁著表弟結婚的由頭還是回家了舞骆。 說實話钥弯,在回家之前是有過期待的,期待看到家...
    娜漾心情閱讀 221評論 0 0