Test t = new Test();
Thread.sleep(1);
//map.put("第"+(i++), wr.get());
list.add(t);
t=null;Test对象被list引用了,t=null并没有释放掉对象

解决方案 »

  1.   

    对呀,按理说应该是内存溢出的啊,但是通过查看空闲内存可以知道,JVM的确进行了垃圾回收!
      

  2.   

    System.out.println(Runtime.getRuntime().freeMemory());
    这个不是一直打印内存在减少?
      

  3.   

    Java不是C++,你说为什么第一段代码应该造成内存溢出??要在Java里写内存溢出可不像在C++里那么简单。
      

  4.   

    finalize()是当垃圾回收器确定不存在对该对象的更多引用时,对象的垃圾回收器调用该方法。
    两段代码最重要的区别在于t = null的位置。
    1中代码修改:while (true) {
          try {
            Test t = new Test();
            Thread.sleep(1);
            t = null;
            list.add(t);
            System.out.println(Runtime.getRuntime().freeMemory());
          }
    }这样和2一样会调用finalize()。
    修改前t = null根本没有释放掉Test对象,自然不会调用finalize()。
      

  5.   

    to c2one :的确是一直在减少,但是过一会还会增多,因为进行了垃圾回收!可是我却没有看到我的finalize()的运行!
    to jamesfancy :
    事实上的确没有溢出,这也是我比较迷糊的地方!
    JVM在这过程中进行了垃圾回收,但是我却没有看到我的finalize()方法运行!难道它回收的是其它的内存?
      

  6.   

    to:wunan320 t对像在t=null的时候就以经变成游离对像了,因为没有任何对像持有它的引用了!接下来的list.add(t)是把null值放进去了!
      

  7.   

    to c2one 我还真没试过持续一个小时,,我中午午休的时候试试!
      

  8.   

    第一个中把“list.add(t);”注释掉就可以看到垃圾回收了。
      

  9.   

    to bao110908 :其实我就是在找一个好的办法使List中的对像内存能够被释放!一个好的办法是list用完之后直接清空,然后将list=null但是在三层架构中,我实在无法知道view层何时能够用完我Action中的list对像!迷茫啊!大家说用Action的finalize()方法进行清理工作会不会有什么后遗症呢?
      

  10.   

    个人的猜测,当内存使用到一定量时。
    jvm会把长期没有使用的对象,放到硬盘里,从而释放了一部分内存上的空间。
    代码1中,没有任何对象被释放,只是换了个存储的空间而已。
    个人意见。
      

  11.   

    Java对内存的管理基本包办完了,一般而言使用Java也没必要为内存当心吧.还有就是finalize()方法的调用完全依靠JVM,很难确定它会在什么时候被调用到....其实Java的内存管理我们应该很放心才对,特别是现在的JVM,都非常强大....一般我使用ArrayList都不限制大小的喵....
      

  12.   

                    list.add(t);
                    t=null;
    这表示t指向的原来对象没有被释放,因为list已经引用了这个对象JVM中所指的空闲对象是没有被其它非空闲对象引用时,才会释放的。所以上面的t不释放,而且如果你去掉了Thread.sleep(1);会很快就内存溢出。WeakReference<Test> wr = new WeakReference<Test>(t);
    list.add(wr);
    这样wr是不会被释放的,但是t是可以被释放的(WeakReference的功能)
      

  13.   

    to wunan320 :我想不大可能,因为我这个类没有实现序列化接口,它是无法序列化的!to cangyue87JVM在回收某对像所占用内存空间的时候,会先运行该对像的finalize()方法的,这在我第二段代码中可以体现出来!
      

  14.   

    to ChDw :
    因为项目中用到了很多的List 所以想利用JAVA的弱引用帮助JVM清理其被占用的内存空间,但是前台用的是freeer,因为现在List中存的是WeakReference,freeer用不了!
    所以我想找个其它办法能够帮助JVM清理List所占用的内存空间!还不影响我使用!
      

  15.   

    回15楼:
    是的,但是想依靠手动调用finalize()或者重写finalize()是管理不了内存的,JVM对finalize()的调用全看RP.....其他正如14楼说的....我是这么认为的,既然我们选择使用Java,就不用为内存操心.import java.util.ArrayList;
    import java.util.List;public class Test 
    {
      @Override
      protected void finalize() throws Throwable 
      {
        super.finalize();
        System.out.println("==> 开始回收垃圾啦");
      }  public static void main(String[] args) 
      {
        // Map map = new HashMap(50);
        List<Integer> list = new ArrayList<Integer>(10);
        int i = 0;
        while (true) 
        {
          try 
          {
            Thread.sleep(100);
            for (Integer j = 0; j < 10; j++) 
            {
              list.add(j);
            }
            list.add(i);
            i++;
            for (Integer k : list) 
            {
              System.out.println(k);
            }
            System.out.print("------------------------");
            System.out.println(Runtime.getRuntime().freeMemory());
          } 
          catch (Exception e) 
          {
            e.printStackTrace();
          }
        }
      }
    }JVM貌似在从其他地方释放内存,不过一直执行下去的话,迟早会溢出....
      

  16.   

    我只能说你将所有东西都放在List里面去,而不考虑内存大小问题。是一个非常非常烂的设计 如果考虑性能就应该是使用Cache,也就是限定内存中最多的缓存对象个数。当超出范围时就释放部分,当没有在缓存中找到时从数据库、文件等中再读取出来绝对不可以将所有东西不加考虑就都放入list中
      

  17.   

    to cangyue87 :但是我第一段代码是典型的JAVA内存泄漏!
    只要程序还在运行,就算我不往list内添加对像了,list内所有对像依然不会被自动回收,除非我将list手工清理一下!但现在我不知道该何时清理list!
      

  18.   

    to ChDw :我只是想尽量地去帮助JVM回收垃圾,尽量避免内存泄漏,尽量从根本上解决问题!用Cache固然是好,但那是我的回马枪,轻易我是不会用地!ibatis自带cache不知道怎么样!
      

  19.   

    午休了,回来继续研究,我看JAVA还不如把DELETE操作符请回来了,只有程序员自己才最清楚对像什么时候该被清理!余下的忘记清理的再由JVM帮助清理不是很好么,,,呼呼,,可能我对JVM学习得还不够到位吧,总感觉有劲使不上!
      

  20.   

    楼主,使用Java就不要怕占用内存。Java如果不占用内存它会很不舒服的!
    Java的内存回收全靠JVM,你手工是不能控制的。当然,适当的把不用的对象引用置为空(释放引用)可以帮忙JVM更快的回收内存。Java中几乎不存在内存泄漏的概念,因为内存都由JVM自己管理了。你千万不要用C++的内存管理的眼光来看Java。Java出现的目的之一就是尽量避免C++中那些复杂的内存操作。要清空List,你可以用list.clear()方法。最后说一句,就算是一个大型的Java应用,也可以不写任何finalize()
      

  21.   

    java手工回收内存的机制不能立刻回收内存,也是JVM自己根据判断来回收内存的
      

  22.   

    我只是想尽量地去帮助JVM回收垃圾,----
    根本错误的做法,你只应该将你认为没有用的对象置空,JVM就会自动回收,你不需要理会这个过程
    我还是那句话,你根本不应该将所有对象无限制的放入list中!
      

  23.   

    finalize()
    知道这个东西,没用过
    有必要用吗?
      

  24.   

    Java自己做主来控制回收内存,即时你使用了gc()
      

  25.   

    to   jamesfancy   : 
    事实上的确没有溢出,这也是我比较迷糊的地方! 
    JVM在这过程中进行了垃圾回收,但是我却没有看到我的finalize()方法运行!难道它回收的是其它的内存?
    其实你是看不到Java内存回收的,也许你可以根据内存使用值的变化来判断。但是你又如何知道它到底回收了些什么东西呢?你之所以没看到finalize()方法运行,那是因为那个对象没根本没被回收。如上面很多朋友指出的那样,你在t = null之前使用list.add(t)将t所指的对象引用添加到了一个list当中。这样一来,现在t所指的这个对象就存在两个引用,一个是t,另一个在list中。之后你t = null,释放了一下引用,list中还存在另一个,所以对象是不可能被回收的。你在t = null之后加一句list.clear()试试。
      

  26.   

    TIJ里面有关垃圾回收和WeakReference的描述应该已经很清楚了呢
      

  27.   

    (1)把你的程序运行了大约一个半小时,内存终于溢出
    输出的代码片断:
    -----
    32
    40
    104
    64==> 开始回收垃圾啦
    Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    ==> 开始回收垃圾啦
    ==> 开始回收垃圾啦
    ==> 开始回收垃圾啦
    ==> 开始回收垃圾啦
    ==> 开始回收垃圾啦
    ==> 开始回收垃圾啦
    ==> 开始回收垃圾啦
    ==> 开始回收垃圾啦
    ==> 开始回收垃圾啦
    ==> 开始回收垃圾啦
    ==> 开始回收垃圾啦
    ==> 开始回收垃圾啦...
    -----
    (2)从Thinking in JAVA中抄出来的:
    容器类中有一种特殊的Map:WeakHashMap,它被用来保存WeakReference。它使得“规范映射” (canonicalized mappings)更易于使用。在这种映射中,每个“值”只保存一份实例以节省存储空间。当程序需要那个“值”的时候,便在映射中查询现有的对象,然后使用它(而不是重新再创建)。可将“值”作为“规范映射”的一部分,一同初始化,不过通常是在需要的时候才生成“值”。
    这是一种节约存储空间的技术,因为WeakHashMap允许垃圾回收器自动清理“键”和“值”,所以它显得十分便利。对于向WeakHashMap添加“键”和“值”的操作,则没有什么特殊要求。WeakHashMap会自动使用WeakReference包装它们。允许清理元素的触发条件是,不再需要此“键”了
      

  28.   

    竹子教你如何结贴
    http://topic.csdn.net/u/20080110/19/7cb462f1-cac6-4c28-848e-0a879f4fd642.htmlPS:这株竹子不是紫色的那株...
      

  29.   

    原则1:不要怀疑JVM
    原则2:不要干涉JVM
      

  30.   

    我把楼主的代码改了一下
                    Test t = new Test();
                    //WeakReference<Test> wr = new WeakReference<Test>(t);
                    //t = null;
                    //Thread.sleep(1);
                    //map.put("第"+(i++), wr.get());
                    list.add(t);
                    //t=null;
                    //System.out.println("freeMoney==>"+(Runtime.getRuntime().totalMemory()-Runtime.getRuntime().freeMemory()));
                    System.out.println(Runtime.getRuntime().freeMemory());也就是没有一个垃圾,看看会打印什么,结果是不断的出数字,然后不停的减小,从500多到620多(我是1G的内存,把虚拟内存关了)。最后自然是内存溢出。但是却打印出
    ==> 开始回收垃圾啦
    这个不好理解,这里回收的是什么呢?我大概看了一下,在出现java.lang.OutOfMemoryError之前大概打印了200多行开始回收垃圾啦,那这个垃圾是什么呢?JVM内部的也没这么多吧,难道是强行的把Test给回收了?