熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> JSP教程 >> 正文

Java人員談論內存洩露問題分析

2013-11-15 11:37:42  來源: JSP教程 

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

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.