0

我正在玩一个可怕的数据结构,它基本上是一棵树,每个节点都将对其子节点的引用存储在一个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

4 回答 4

1

你的问题有点不清楚 - 你真的得到了 OutOfMemoryErrors 吗?你想解决什么问题?您看到测试用例中表现出的行为有几个原因:

  1. 当某些东西不再可以从 GC 根访问时,垃圾不会被收集——它只是变得有资格进行垃圾收集。GC 通常仅在分配失败时触发。由于您实际上并没有在循环中分配更多内存以使引用无效,因此完全有可能 GC 尚未运行。

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

于 2012-07-28T21:25:03.397 回答
0

垃圾收集器的行为是复杂的,不同的垃圾收集器可以使用根本不同的方法。你不能指望垃圾会立即被回收,即使你明确地调用它。

于 2012-07-28T21:10:40.693 回答
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

于 2012-07-28T21:22:04.413 回答
-4

您可以使用代码在 10000 个循环中手动调用一次垃圾收集

System.gc();

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

于 2012-07-28T21:00:30.410 回答