为什么Java垃圾收集器不收垃圾?

时间:2012-07-28 20:56:34

标签: java garbage-collection

我正在玩一个基本上是树的可怕数据结构,每个节点都在HashMap个对象中存储对其子节点的引用。每当我需要通过将后一个子树设置为新根时,除了一个除掉根和所有子树之外,我就会遇到麻烦。我认为这可能是我的数据结构中的一些错误,也许是我忘了在那里的一些参考,所以什么都没有资格进行垃圾收集。但我想先尝试一些更简单的方法,并实施以下测试:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class MyNode {
        MyNode next;
        int somedata;

        public MyNode(MyNode n) {
            next = n;
            somedata = 0;
        }

        public static void main(String[] args) throws IOException {
            MyNode p = new MyNode(null);
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            for (int i=0; i<10000000; i++) {
                MyNode n = new MyNode(p);
                p = n;
            }
            while (p!=null) {
                MyNode p1 = p.next;
                p.next = null;
                p = p1;
            }
            in.readLine();
        }
}

当main到达in.readline()时,我可以在htop中看到该进程仍然为自己分配了250MB左右,并且没有任何内容被释放。我显然是第一次尝试简单地做

p = null;

而不是while循环。但它没有用,所以我想出了以前的代码。

4 个答案:

答案 0 :(得分:1)

您的问题有点不清楚 - 您实际上是在获取OutOfMemoryErrors吗?你想解决什么?您可以通过几个原因看到测试用例中出现的行为:

  1. 当GC根目录无法访问垃圾时,不会收集垃圾 - 它只是有资格进行垃圾回收。 GC通常仅在分配失败时触发。由于您实际上并没有在循环中分配任何内存以使引用无效,因此GC完全可能尚未运行。

  2. 即使收集垃圾,堆中的内存通常也不会返回给操作系统 - 因此从操作系统的角度来看它不会产生准确的答案。使用VisualVM或者像jmap和jhat这样的工具将是找出实际上仍然在堆上的内容的最佳方法。

答案 1 :(得分:0)

垃圾收集器的行为很复杂,不同的垃圾收集器可以使用根本不同的方法。即使您明确表示,也不能指望垃圾立即被回收 调用它。

答案 2 :(得分:0)

我之前见过这个。

htop不是衡量JVM内存利用率的最佳方法。它一直显示出高分。 VM也喜欢将其堆分配得尽可能高。

我建议使用visualgc或jconsole跟踪JVM附带的jps和jpstat。 http://java.sun.com/performance/jvmstat/#Tools

此外,你有一个可以快速创建大量对象的循环,因此gc现在可能有时间进入。 System.gc不保证实际执行。这是一个暗示,但它通常有效。

另请参阅有关Java堆利用率的帖子: http://it.toolbox.com/blogs/lim/how-to-get-details-on-jvms-heap-utilization-10609

答案 3 :(得分:-4)

您可以使用代码

在10000次循环中手动调用一次垃圾回收
System.gc();

然而,有一些副作用,例如垃圾收集器使用额外的cpu时间。