http://www.cnblogs.com/dotnetdoor/archive/2008/06/09/1216125.html
看到一篇内存泄露的文章:
文章中举了一个内存泄露的例子:
Vector v = new Vector(10);
for (int i = 1; i<100; i++)
{Object o = new Object();
v.add(o);
o = null;
}//文章中描述:
  在这个例子中,循环申请Object 对象,并将所申请的对象放入一个Vector 中,如果仅仅释放引用本身,那么Vector 仍然引用该对象,所以这个对象对GC 来说是不可回收的。因此,如果对象加入到Vector 后,还必须从Vector 中删除,最简单的方法就是将Vector对象设置为null。在我看来 vector中的 o 已经都统统指向了 null 而 new 出来的Object 已经没有对象再应引用它了,没用被应用的对象就应当被回收啊,所以这些new Object会被释放
请教各位,我的想法错在哪里?

解决方案 »

  1.   

    首先理解什么是引用,什么是对象。
    java中我们是通过引用来操作对象的。
    比如Object o = new Object();
    这里的o是引用,根据o能找到新创建的对象,但是o并不是这个对象。
    打个比方,o就是一个门牌号,通过门牌号能找到放对象的地方。
    v.add(o);就是你把门牌号放到里面了,也就是说v通过内部的信息还能找到对象,对象不是垃圾。
      

  2.   

    一楼说的有道理,“o = null;”这条语句说的是将引用置空,垃圾回收器回收的是引用所占用的栈,而用new实例化的对象仍然占据着堆的空间(因为对象生成事默认的构造函数已经将其初始化,而现在仍不为null),所以没有被回收。个人见解,希望对你有帮助。
      

  3.   

    虽然o=null了但还有其他的引用这个对象所以不会被GC回收
      

  4.   

    在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点,首先,这些对象是可达的,即在有向图中,存在通路可以与其相连;其次,这些对象是无用的,即程序以后不会再使用这些对象。如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存
    在C++中,内存泄漏的范围更大一些。有些对象被分配了内存空间,然后却不可达,由于C++中没有GC,这些内存将永远收不回来。在Java中,这些不可达的对象都由GC负责回收,因此不需要考虑这部分的内存泄露。   注意事项:   1.最基本的建议是尽早释放无用对象的引用。如:   ……   A a = new A();   //应用a对象   a = null; //当使用对象a之后主动将其设置为空 
    这是我看的别的资料说的,自己也有点迷惑了,希望更多好好的讨论  …。 
      

  5.   

    一楼的意思是不是说,通过v还能访问到o,所以虽然o=null,但o指向的那个对象仍然能通过v访问到,所以GC不会回收的
      

  6.   

    v.add(o);意味着对象o,增加了一个新的引用(如果v中没有指向o的引用,如何通过v来访问到o)
    o=null,只是去掉了其中的一个引用。
      

  7.   

    其实Java中不可能存在内存泄漏,因为GC会在必要的时候回收内存。这个例子没有体现内存泄漏,但是用来理解内存泄漏的潜在发生可能还是可以的。不需要那么复杂,一个非常简单的例子就能说明问题:Object o1 = new Object();Object o2 = o1;o1 = null;  //  这时o1指向的那个对象回收了吗?没有,因为它还被o2引用着o2 = null;  //  这样才能回收实际应用中,只要o2的作用域很小,不执行o2=null也是没有问题的,因为只要o2过了它的生存期,它指向的对象就能被回收。结论是,作用域越大的变量,越要引起重视,因为它可能占用着某些对象引用而导致对象不能被回收。换句话说,尽可能地缩小变量的作用域——这也是你在Java中关于内存方面能做的唯一努力了。
      

  8.   

    恩,刚翻了下书,书上说“垃圾回收器只知道释放那些经由new分配的内存”,也就是堆吧,呵呵,希望不会误解大家。
      

  9.   

    看看有向图吧,
    Object o = new Object();
    v.add(o);有向图里new出来的对象有两个通路和其关联o = null;
    关闭了其中一条通路仍然可以通过v.get(0);访问该对象
    就是说v这个引用指向的对象和new出来的Object对象依然有关联
    要么v.remove(0);要么v=null;
      

  10.   

    垃圾回收的机制就是,对于每一个创建的对象,JVM的内存管理器都会设置它的引用数为0,每对这个对象的引用多了一个,引用数加1,JVM会有一个线程不断的判断每一对象的引用数,当引用数小于0时,从堆中释放改对象。对于例子中的o。
    o=null前,它的引用数为1.
    o=null后,引用数为0,仍然不小于0,因而不释放。
    如果加入,v.remove(i),引用数小于0,释放对象o在堆中的空间,此时内存得到回收。gc的管理模型采用树一样的结构,来保证所有的对象都是可达的。但是如果因为某些原因,还是会有一些对象不再使用,但一直被引用,此时gc不会回收这些对象,就出现了所谓的内存泄露。Java中存在内存泄露,17楼的说法是错误的!!
      

  11.   

    to 22楼:内存泄漏的定义是,申请的内存没有办法释放才称为内存泄漏。比如在C中,
    int *p = malloc(sizeof(int));
    p = malloc(sizeof(int));
    delete p;p之前申请那块内存就没有办法释放。delete p只是释放了p后来申请的那块内存。这叫做内存泄漏!而Java中不可能存在没有办法释放的内存,所以Java中不存在内存泄漏。反驳我的话,请你举反例。
      

  12.   

    这个不叫内存泄露,这是内存溢出,也就是说 JVM 已经没有可以掌控的内存空间分配给新产生的对象了。
      

  13.   

    JVM 中常见的内存溢出错误有:OutOfMemoryError: heap space
    OutOfMemoryError: PermGen space
      

  14.   


    “没有办法释放”不能作为指标,我也看多C和C++内存方面的东西,从来没见过这种提法!
    另外C/C++中的提法不一样,他们在这方面比较严谨 malloc / free 必须成对使用,c++中
    new / delete 必须成对使用这位兄弟笔误了一下 malloc 和 delete 配对了~呵呵
      

  15.   


    请看 http://en.wikipedia.org/wiki/Memory_leak,这应该是权威解释了吧?这里明明说到:...where the program is unable to release memory it has acquired.
      

  16.   

      不会哦,我以前这这样写代码,但是通过Vector,访问不到加入的对象了 啊?报NULLPointerException
      

  17.   

    对于java,其实是不必象其他语言一样,关注变量以及对象的释放问题.因为有垃圾收集机制.能处理大部分情况.通常而言,关于java这方面的问题是集中在垃圾收集机制什么时候起作用:java官方自己对于这方面的描述是:不知道什么时候会确实回收,即使是显式地调用了垃圾回收的代码.java还是存在内存泄漏(不管怎么叫吧,就是内存没有被释放)的问题的,关于这方面的例子,记得应该在<java编程思想>上有示例代码,他是要说明的是在某些情况下,即使调用了垃圾回收代码,也不能确保这些内存被回收了.不过无论怎么说,在实际中编写java程序无需考虑释放内存问题,很多实际代码都没有在最后赋null.
      

  18.   

    不多争论,事实证明一切; public static void main(String[] args) {
    Vector vector=new Vector();
    Object object=new Object();
    vector.add(object);
    System.out.println("before \"object=null\" objcet==="+object);
    object=null;
    System.out.println("after \"object=null\"  object==="+object);
    System.out.println("vector.get(0)==="+vector.get(0));
    }
      

  19.   


    火龙果 大哥,个人觉得 这个是典型的 内存泄露 例子,因为这里只 new 了99个Object ,不存在 内存不够问题
      

  20.   

    执行结果:
    before "object=null" objcet===java.lang.Object@18a992f
    after "object=null"  object===null
    vector.get(0)===java.lang.Object@18a992f明显的没有执行object=null之前object和vector.get(0)指向的是同一个对象
    而object=null;这里只能理解为把object这个引用和java.lang.Object@18a992f地址指向的数据的联系给断开了而已,并不是将java.lang.Object@18a992f指向的内存的数据都当做垃圾回收
      

  21.   

    不需要把那个 Vector 置为 null,如果那个 Vector 是局部变量,那只要离开了局部变量的作用范围,那么这一块区域就是不可用的了,在垃圾回收器启动时会将其进行回收的。因此,一般也建议编写代码时尽可能地缩小局部变量的作用范围。
      

  22.   

    最简单的例子,打开文件没关闭,这个java管不了啊
      

  23.   

    首先要搞清楚什么样的对象会被JVM扫描后当作垃圾回收。当一个对象不被任何引用指向的时候(不知道这么说合理否),它才会被GC回收,而虽然o与new Object()切断了联系,但仍有v[index]指向new Object()。故不能被GCing。
      

  24.   

    好像在哪里看到过,如果JAVA中引用了C代码用malloc申请的内存块,并且没有在引用的JAVA对象的finalize方法里写相应的代码来释放这个C代码申请的内存,JAVA的垃圾回收好像是回收不了的。
    想起来了,是thinking in java里面的
      

  25.   

    呵呵,幸勤的小蚂蚁。实际上就算显式地 = null 那也是无济于事的,这样做只是把变量指向了一个 null,但是原本的数据会被扔掉,同样需要 GC 进行清扫。GC 一般情况下都是在那里打盹,一旦 JVM 内存开始紧张的时候,GC 才会开始工作,呵呵。
      

  26.   

    关键是栈和堆的概念  特别是java在处理 一楼说的很对 Object o = new Object() ;o是在栈一个单元,记录的是new object()在堆中开辟的内存地址,所以每当你使用v.add(o)实际上也就将地址copy一份记录下来,所以当o=null时只是将栈中记录地址的单元清空,而v还是有指向堆中的内存单元。GC只存在于堆中,所以在堆中开辟的内存单元在栈中还有一个记录它地址的引用,所以至少现在是不能被回收的。  
      

  27.   

    Vector v = new Vector(10);
    for (int i = 1; i<100; i++)
    {Object o = new Object();//o 是一个引用在这个是这这个应用存放的是刚刚new出来的object的地址
    v.add(o);// 在v中添加了指向object的地址
    o = nul…… //所以在这个时候改变o的引用是对v不起作用的,v中存放的并不是o的值,而是当时o的指向的object的引用地址
      

  28.   

    既然V还引用object,那么这个object就还可以被用到,为什么说是内存泄漏?还是不懂~
      

  29.   

    操,妈个B的,搞了我想半天,例子没贴全,注释也是代码的一部分!!整个例子的意思如下:
    Vector v = new Vector(10);
    for (int i = 1; i<100; i++)
    {Object o = new Object();
    v.add(o);
    o = null;
    }
    //balababala........................这里使用v
    //但是下面的程序不会再使用v了,这里如果不将v=null的话,就会一直占用堆空间。在另一个角度来说,貌似内存不见了一部分,“变小”了,如果有N个类似这样的v,就会导致内存溢出问题。
      

  30.   

    Life lies in movement, programing lies in thinking.