【发布时间】:2012-07-28 20:56:34
【问题描述】:
我在玩一个可怕的数据结构,它基本上是一棵树,每个节点都将对其子节点的引用存储在 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 循环。但它不起作用,所以我想出了以前的代码。
【问题讨论】:
-
小心 - 分配给进程的内存量不与用于对象的内存量相同。大多数进程在分配内存后不会将内存返回给操作系统,因此即使垃圾收集器确实运行了,您也不一定会看到分配给进程的总内存反映了它。
-
在 Java 命令行应用选项
-XX:+UseConcMarkSweepGC以使用并发收集器。否则我认为 HotSpot 只会在分配时触发集合。 -
使用 HTOP 绝对是衡量 java 任务内存使用的错误方法,您需要使用分析器 - 如果您使用的是 JDK 1.6 或更高版本,那么 VisualVM 附带 JDK
-
我使用 HTOP 是因为我对我的程序使用的实际内存感兴趣。但我想我明白了,可能 Java 不是完成这种分配/释放工作的最佳工具
-
Lorenzo,如果您事先知道您真正需要多少内存,那么只需将 Java 的最大堆限制为该大小。这将迫使 GC 更加雄心勃勃地回收内存。如果堆上有可回收的内存,您可以绝对确定 GC 不会允许内存不足的情况。