请问JAVA里面存在内存泄露问题吗?今天面试的题目,看到这个问题我晕了!如果有泄露的情况,也就是说GC做的不好!到底是怎么回事情,最后有代码说服我!

解决方案 »

  1.   

    据说是有的,上次在校内bbs上看到有人提起,可以google看看
      

  2.   

    按Java的理论是应该不存在的但是java编译器是用什么编的?它有没有呀?这就得问问有研究的人了
      

  3.   

    java的自动单元收集避免了内存丢失等动态内存分配导致的问题,java也不支持指针,这杜绝了内存的非法访问。
      

  4.   

    其实,是存在内存泄露的
    http://blog.csdn.net/hbcui1984/archive/2006/11/07/1370785.aspx
      

  5.   

    当然存在
    effective java中还举了例子
      

  6.   

    我认为,如果简单说“Java 存在内存泄漏问题”,那是在有意或无意地混淆视听。首先要明确什么是“内存泄漏”。恐怕大多数人的概念里,“内存泄漏”指的是 C/C++ 里那种“分配了一块内存,用完后没有释放,也不再有指针指向这块内存”。程序执行到这,后面的程序再没有任何办法使用这块内存,却也永远无法释放它(除非程序终止)。可以肯定地说,Java 中是不会出现上面这种情况的!所谓“Java 的内存泄漏问题”,其实指的是另一种完全不同的情况,即所谓的“无意识保留”。也就是说,当程序执行到某处时,某个对象从程序逻辑上已经不再需要了,但从程序语法上却还保留着(被某个变量所引用),造成 GC 无法对其进行回收。这种所谓的“泄漏”,其危害程度相对比较小,而且往往能够“自愈”。我们讨论“Java 是否存在内存泄漏问题”的时候,不要停留在得到一个“存在”或者“不存在”的结论,而是要搞清楚它的实际含义,这样才能真正对我们的软件开发工作有所助益。
      

  7.   

    maquan说的很专业啊。
    Java程序内存泄漏都是指应用程序编写不当,造成无法内存对象无法回收造成的,和Java本身没有关系,和开发者有关。
    现在推荐使用Java 6.0的ref API,SoftReference, WeakReference & PhantaomReference能帮助开发者减少内存泄漏的现象。详细可以看Java的Document。
    另外NetBeans和Profiler也可以帮你检测程序是否有内存泄漏问题,在哪儿出现的等等。
      

  8.   

    我个人认为:java是会存在内存泄露的。垃圾回收机制是回收长时间不用的内存块,如果你有一个对象长时间没有使用,被GC回收了,如果这时候有一个引用指向了这个对象,不就发生了内存泄露了吗?
      

  9.   

    是的,存在这样的问题。maquan说的很对
      

  10.   

    这个问题怎么说呢 
    大家都知道内存泄漏指用了内存后没有释放。但是这个释放的动作是谁触发的呢?当然是写程序的人。难道你在c++中显式的释放一个对象的时候,c++会不给你释放?所以说内存泄漏是由人决定的而不是某种语言。
    c++和java的一个区别就是c++需要显式的释放对象,而java是由gc来完成的。对于程序员来说前者可能会麻烦一点,但是他的效率也好于后者。不过对目前的硬件环境而言这点效率好像已经不算什么了。java的gc只是回收不再用的对象。
    最后一句话 内存泄漏是由人决定的而不是某种语言
      

  11.   

    存在啊,有一种情况就是使用Java的本地方法调用,这时候调用一些c语言写的方法或程序,而这些程序存在内存泄露。两一种情况就是网上举的例子,用java模拟一个堆栈,在出栈的时候的一些失误引起的。
      

  12.   

    存在, 如: int i,j; i=i+j; 当i和j都足够大的时候。
      

  13.   

    这要看内存泄漏的定义了。举例来说,内存泄漏可能会有一种比较典型的定义,就是当一个程序退出时,是否有未归还给操作系统的内存。(假设操作系统自己不会自动收回)。对于这种情况,如果有的话,那是Java虚拟机的问题。
    另外楼上的那个叫溢出,不叫内存泄漏。
      

  14.   

    maquan说的极是,讨论这个议题之前我们首先要明确什么是“内存泄漏”,否则鸡同鸭讲. 如果你写一个死循环不断的new 不同的对象,最后JVM抛出out of memory,然后说:看,这不就是java内存泄漏了吗? 那我没话说了. 另外,这也不是投票, 只说存在还是不存在是没啥意义的.
    java的这个“内存泄漏”话题已经被说的很玄乎,但我觉得程序员嘛,靠山吃山,最好用实际程序说明问题.
    一段被流传很广的如下代码(参考上面某楼的链接http://blog.csdn.net/hbcui1984/archive/2006/11/07/1370785.aspx)Vector v=new Vector(10);
    for (int i=1;i<100; i++)
    {
     Object o=new Object();
     v.add(o);
     o=null; 
    }
    说是加上o=null;gc会回收对象占用的内存,提高内存使用率,实际上是脱裤子放屁. 
    运行以下一段代码就会明白,注释或者不注释//mybyteOBJ=null;结果应该是一样的,
    不要告诉我System.gc();不一定总是有效之类的话,也许应该另开一个Thread讨论System.gc();的问题:)
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
        long total = 0;
        Vector vt = new Vector();
        System.gc();
        long oldmem = getFreeMem();
        for (int i = 0; i < 1000; i++) {
         Integer mybyteOBJ=new Integer(i);
          vt.add(mybyteOBJ);
          //mybyteOBJ=null;
          System.gc();
          total = total + (oldmem - getFreeMem());
        }
        System.out.println("total=" + total);
      private long getFreeMem() {
        long mem = Runtime.getRuntime().freeMemory();
        return mem;
      }
      事实上java内存分配远没想象的那么简单,例如上面的代码,往vector加Object,内存消耗也不是增加一倍(或者以上),而是远远小于一倍,到此我猜你也许想说点什么,欢迎继续:)还有其他例子,不一一列出了. 
    但无论是啥情况,JVM都可以很好的进行内存回收.那种所谓"即使每次运行少量泄漏,长期运行之后,系统也是面临崩溃的危险。"是荒谬的,除非你的代码错误,否则JVM会在崩溃之前很好的回收内存(很难想象有人会把JVM配置成"长期运行之后"再进行gc)
      

  15.   

    vector加Object时只是添加Object的地址,并不是Object的所有内存,内存当然不会成倍的增加了Object是new 时分配的地址及内存.
      

  16.   

    maquan('ma:kju) ( ) 信誉:100    Blog  2006-11-23 11:37:36  得分: 0  
     
     
       
    我认为,如果简单说“Java 存在内存泄漏问题”,那是在有意或无意地混淆视听。首先要明确什么是“内存泄漏”。恐怕大多数人的概念里,“内存泄漏”指的是 C/C++ 里那种“分配了一块内存,用完后没有释放,也不再有指针指向这块内存”。程序执行到这,后面的程序再没有任何办法使用这块内存,却也永远无法释放它(除非程序终止)。可以肯定地说,Java 中是不会出现上面这种情况的!所谓“Java 的内存泄漏问题”,其实指的是另一种完全不同的情况,即所谓的“无意识保留”。也就是说,当程序执行到某处时,某个对象从程序逻辑上已经不再需要了,但从程序语法上却还保留着(被某个变量所引用),造成 GC 无法对其进行回收。这种所谓的“泄漏”,其危害程度相对比较小,而且往往能够“自愈”。我们讨论“Java 是否存在内存泄漏问题”的时候,不要停留在得到一个“存在”或者“不存在”的结论,而是要搞清楚它的实际含义,这样才能真正对我们的软件开发工作有所助益。  
     
    ===================================================================大致同意,但是实际上C/C++那种类型的内存泄漏,在JAVA中同样存在,你说的后者是开发人员造成的泄漏,前者是虚拟机内部的内存泄漏,这个在使用JNI的时候比较多。
      

  17.   

    严格来说,我想绝对没有人百分之百相信JVM在任何情况下都不会发生内存泄漏现象,不可能做到如此完美。
      

  18.   

    好了好了, 都别争了,  java 是最完美的语言, 绝对不出任何的错误,行了吧
      

  19.   

    一直以为java不存在memory leak......看了maquan的文章弄清楚,多谢maquan.
      

  20.   

    已经猜到有人会说:vector加Object时只是添加Object的地址...仔细再看看就可以明白,当接下来加上mybyteOBJ=null;后,vector里头mybyteOBJ就再也不能只是地址引用了,无论如何必须有其他地方的内存存放mybyteOBJ.这也是为什么说加上mybyteOBJ=null;是多此一举.事实也是如此.
    我的观点还是只管写好你自己程序,不用操心JVM的所谓"内存泄漏".
    倒是有其他几种情况值得讨论.
    1.程序访问JVM之外的资源,例如文件系统,看以下一段程序
        writeFileTest();
        System.gc();
        System.out.println("test ok");
        
      private void writeFileTest() {
        try {
        FileOutputStream  fs=new FileOutputStream("D:/youtest.log", true);
        Writer fw =new OutputStreamWriter(fs);
        fw.write("this is a test");
        fw.flush();
        }
        catch (Exception ex) {
          ex.printStackTrace();
        }
      }
    在System.gc();设个断点,然后debug运行程序,按道理writeFileTest()方法结束,那么它方法内的变量也随之销毁,释放资源.但实际上如果在运行System.gc()之前用写字版(一定用这个程序)打开的话,它会提示文件正被另外的程序使用...
    这是因为上面的程序在writeFileTest()里头没有调用fs.close()显式的关闭资源. 但是在同一个JVM里头,当你再次访问youtest.log时,JVM知道该怎么做,不会让你对"方法结束,变量销毁"感到失望,但对JVM之外的程序,例如上面的写字板则是另外一回事,
    所以对类似的第三方资源,应该显示的调用close()之类的方法显式的关闭资源,而不应该依赖gc. 幸运的是java对类似的资源都有类似close的方法,你只要照着做,gc的事让JVM来吧.
    2.非简单new 出来的变量资源, 最典型的是JDBC 连接池获得的Connection. 
    private void ConnTest(){
      Connection conn=pool.getConn();
      .....
      conn=null;
    }
    你不能指望ConnTest()方法结束,里头的conn变量销毁, 因为你不是简单的new 出来,而是从pool里头获得引用,方法结束,pool并没有结束,而且你不知道pool如何对待你的引用,所以加上conn=null也未必有用.
    以上这些不应该跟java "内存泄漏"扯上关系,而是活生生的程序错误.
    另外,楼上的可真会掰:)
      

  21.   

    我可以不长篇大论么?我可以copy别人的长篇大论么?我可以不自以为是么?
    首先请某些同学购买或下载《effective java》来看,谢谢。
    以下是第二章:创建和销毁对象http://www.matrix.org.cn/resource/upload/forum/2005_12_13_182559_zJoNyezkbm.pdf
    请找到 第5条:消除过期的对象引用
      “当你从一种手工管理内存的语言(比如C或C + +)转换到一种具有垃圾回收功能的语言的
    时候,你作为一个程序员,工作会变得更加容易,因为当你用完了对象之后,它们会被自动
    回收。当你第一次经历对象回收功能的时候,你会觉得这有点不可思议。这很容易会让你留
    下这样的印象,认为自己不再需要考虑内存管理的事情了。实际上,这是不正确的。
    ......
    ......
      在支持垃圾回收的语言中,内存泄漏是很隐蔽的(这样的内存泄漏被称为“无意识的对象
    保持(unintentional object retention)”更为恰当)。如果一个对象引用被无意识地保留起来了,
    那么,垃圾回收机制不仅不会处理这个对象,而且也不会处理被这个对象引用的所有其他对
    象。即使只有少量的几个对象引用被无意识地保留下来,也会有很多的对象被排除在垃圾回
    收机制之外,从而对性能造成潜在的重大影响。
    要想修复这一类问题也很简单:一旦对象引用已经过期,只需清空这些引用即可。在上述
    例子的Stack类中,只要一个单元被弹出栈,指向它的引用就过期了。pop方法的修订版本
    如下所示:
    public Object pop() {
    if (size==0)
      throw new EmptyStackException();
      Object result = elements[--size];
      elements[size] = null; // Eliminate obsolete reference
      return result;
    }清空过期引用的另一个好处是,如果它们在以后又被错误地解除引用,则程序会立即抛出
    NullPointerException异常,而不是悄悄地错误运行下去。尽可能早地检测出程序中的
    错误总是有益的。”==================================
    请不要认为获得2002年图灵大奖的图书中存在你能找到的错误,如果你能,那你也不在CSDN发帖子了。
      

  22.   

    一场看得人郁闷的辩论战,也是所谓最无聊的“定义战”。大家不如先明确讨论下“内存泄漏”的定义吧……楼上所说的还是上前面早有人提到的“无意识的对象保留”?
    都多了那么多帖了还没搞清楚吗?另外,个人认为,native代码里面的内在泄漏是JVM以外的事吧?
    要不要算到“Java内存泄漏”里面还有待讨论……不过还好,有不少代码看,这点喜欢,也更能说清问题。^_^
      

  23.   

    个人认为System.gc()适用的范围只是在,密码 、加密算法值密私等重要的保密信息吧。让其在不被使用后,马上让垃圾机制回收清零。win2K就存在这样一个问题。可以通过黑客程序在admin login后从内存中取得密码(当然2000是C++写的,这里提到这点只是以为说明一点问题)。
      

  24.   

    汗,看到标题的第一反映是:该如何才能写出让内存泄露的Java代码呢?
      

  25.   

    http://en.wikipedia.org/wiki/Memory_Leak
      

  26.   

    Effective Java里面的条款5,消除过期的对象引用
        public class Stack {
        private Object[] elements;
        private int size = 0;    public Stack(int initialCapacity){
    this.elements = new Object[initialCapacity];
        }    public void push(Object e){
    ensureCapacity();
    elements[size++] = s;
        }    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);
    }
        }
    }这个程序里面就存在着一个“内存泄露”问题,如果这个栈先增长,再收缩,那么,从这个栈中间弹出来的东西将不会被当作垃圾回收,即使使用栈的客户程序不再引用这些对象了,这是因为栈内部维护这些对象的过期引用
    解决方法,修正pop方法
        public Object pop(){
        if(size == 0)
    throw new EmptyStackException();
        Object result = elements[--size];
        elements[size] = null;
        return result;
    }
      

  27.   

    当然有! 
        1,java的GC只释放你不再指向的对象。如果一些对象你不再使用了,但仍然有指针指向它,那么就不会释放。如List中的元素。  如果不释放的对象足够多,那么内存就会泄露。
        2,Java的GC只释放对象。如果你的Java程序使用了其他资源,而你不手工释放,那么就会发生内存泄露。如,操作系统资源:文件。文件打开后,不关闭,就会造成操作系统问题。还有,操作系统的图形资源。如果不释放,也会发生操作系统问题。另外,还有数据库连接,也会发生内存泄露。
      

  28.   

    某大侠曰:
    在Java中,内存泄漏
    就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中, 存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这 些对象不会被GC所回收,然而它却占用内存。
    -------------
    可见他所谓的java的内存泄漏跟c里面的是两回事,c中的泄漏的内存是不可达的,也就是没有指针指向这个内存区域,而java里面是有指针指向这个区域,只是他对于你的程序来说是没有用的,这是所谓的java的内存泄漏问题。
    比如:程序定义了也 static map 用来做对象的缓存,但是对象没用后并没有把它清除调,而再map中还有他的引用,当然垃圾回收是不会回收这个内存的。
      

  29.   

    呵呵,小弟就是上面那篇链接(http://blog.csdn.net/hbcui1984/archive/2006/11/07/1370785.aspx)的博主,没想到这几天针对这个问题讨论如此热烈,大家的热情小弟敬佩!首先要说明的是,本篇文章我是从IBM developerworks转载过来,虽然对文章中某些内容不敢苟同,但是我不能修改人家的文章,就以原版内容拷了过来。下面再聊聊下面这段代码:
    Vector v=new Vector(10);
    for (int i=1;i<100; i++){
    Object o=new Object();
    v.add(o);
    o=null;
    }
    这段代码,被认为是经典的内存泄漏的代码,其实,本人感觉并无内存泄漏,以下是我的几点看法:
    1.o=null; 对这句代码,我的看法和大多数达人的看法是一致的,即:o是一个局部变量,在超出其作用域时,自动取消对Object的引用,因此,这行代码是没有必要的。
    2.对于v,只要程序中还在使用该Vector,则v就不会释放其引用,并且new出来的100个Object也不会释放其相应的内存,只有当v不再被引用或者超出其作用域时,v的引用才会被取消,这时,new出来的100个Object才可能被释放。
    3.对于new出来的Object,我个人认为只有v对它们有引用关系,o对他们的引用关系在跳出循环之后自动取消了。
    4.为了在是jvm尽快释放不需要的内存,在程序中,程序员可以显式的使用v=null来取消v的引用,这样,容器和其中的对象所占用的内存都可以被释放。
    5.也许可以换种思路理解作者的含义,也许,作者想告诉我们的意思是:虽然是用了o=null,但是并没有释放Object所占用的内存,只有在该Object所在的容器也消亡时,该Object才会释放相应的内存,而要尽早使没用的Object消亡,可以显示的指定v=null;以上是我个人的看法,欢迎大家批评指正。
      

  30.   

    建议某些同学copy东西也应该copy全点, 还是用程序说明问题
    用-Xms1m -Xmx1m JVM参数运行以下YourTest程序, JVM将抛出out of memory错误,于是....
    那个Stack(WrongStack)没有错误吗? 一个实现堆栈数据结构的程序,东西出栈了,堆栈里还保留着这个东西而不清空没有错误(bug)么? 自己程序写错了硬要说是java "内存泄漏"是不厚道的.
    其实下面的这个程序把WrongStack ws=new WrongStack(1);注释掉,换成RightStack ws = new RightStack(1); 加大i的循环次数甚至死循环,很明显JVM还将抛出out of memory错误, 这下不会再说java "内存泄漏"了吧
    如果隐蔽的程序错误叫"内存泄漏",明显的程序错误叫"程序错误",那又算是哪门逻辑呢?import java.util.Vector;
    import java.util.Date;
    import java.util.EmptyStackException;public class YourTest {
      Vector vt = new Vector();
      public YourTest() {
        for (int i = 0; i < 1000; i++) {
          WrongStack ws=new WrongStack(1);
          //RightStack ws = new RightStack(1);
          for (int j = 0; j < 100; j++) {
            ws.push(new Date());
          }
          for (int j = 0; j < 100; j++) {
            ws.pop();
          }
          vt.add(ws);
        }
        System.out.println("test ok");
      }  public static void main(String[] args) {
        YourTest yourTest1 = new YourTest();
      }  class WrongStack {
        private Object[] elements;
        private int size = 0;
        public WrongStack(int initialCapacity) {
          this.elements = new Object[initialCapacity];
        }    public void push(Object e) {
          ensureCapacity();
          elements[size++] = e;
        }    public Object pop() {
          if (size == 0) {
            throw new EmptyStackException();
          }
          return elements[--size];
        }    /**
         * ensureCapacity
         */
        private void ensureCapacity() {
          if (elements.length == size) {
            Object[] oldElements = elements;
            elements = new Object[2 * elements.length + 1];
            System.arraycopy(oldElements, 0, elements, 0, size);
          }
        }
      }  class RightStack {
        private Object[] elements;
        private int size = 0;
        public RightStack(int initialCapacity) {
          this.elements = new Object[initialCapacity];
        }    public void push(Object e) {
          ensureCapacity();
          elements[size++] = e;
        }    public Object pop() {
          if (size == 0)
            throw new EmptyStackException();
          Object result = elements[--size];
          elements[size] = null; // Eliminate obsolete reference
          return result;
        }    /**
         * ensureCapacity
         */
        private void ensureCapacity() {
          if (elements.length == size) {
            Object[] oldElements = elements;
            elements = new Object[2 * elements.length + 1];
            System.arraycopy(oldElements, 0, elements, 0, size);
          }
        }
      }}
      

  31.   


    stevez() 说得不错不错有些偏执了按照你对“内存泄漏”的理解,不管是那个语言(C,C++,还是Java)都不会存在内存泄漏的问题,只是程序员犯的错误而已呵呵