为什么';Java垃圾收集器不收集垃圾吗?
我正在玩一个可怕的数据结构,它基本上是一个树,每个节点都在为什么';Java垃圾收集器不收集垃圾吗?,java,garbage-collection,Java,Garbage Collection,我正在玩一个可怕的数据结构,它基本上是一个树,每个节点都在HashMap对象中存储对其子节点的引用。每当我需要通过将后一个子树设置为新根来清除根及其所有子树(只有一个子树除外)时,我都很难释放内存。我想这可能是我的数据结构中的某个bug,可能是我忘记在那里的某个引用,所以没有任何东西可以进行垃圾收集。但我想先尝试更简单的方法,并实现了以下测试: import java.io.BufferedReader; import java.io.InputStreamReader; import java
HashMap
对象中存储对其子节点的引用。每当我需要通过将后一个子树设置为新根来清除根及其所有子树(只有一个子树除外)时,我都很难释放内存。我想这可能是我的数据结构中的某个bug,可能是我忘记在那里的某个引用,所以没有任何东西可以进行垃圾收集。但我想先尝试更简单的方法,并实现了以下测试:
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();
}
}
而不是while循环。但是它不起作用,所以我想出了前面的代码。您可以使用该代码手动调用10000次循环中的垃圾收集
System.gc();
但是也有一些副作用,例如垃圾收集器使用额外的cpu时间。垃圾收集器的行为很复杂,不同的垃圾收集器可以使用根本不同的方法。你不能期望垃圾被立即回收,即使你明确地说
调用它。我以前见过这个 htop不是JVM衡量内存利用率的最佳方法。它一直显示出很高的分数。 VM还喜欢将堆分配保持在所看到的高度 我建议使用visualgc或jconsole跟踪JVM附带的jps和jpstat。 另外,您有一个快速创建大量对象的循环,因此gc现在可能有时间启动。 gc不能保证实际执行。这是一个暗示,但通常是有效的 另请看这篇关于Java堆利用率的文章:
你的问题有些不清楚-你真的摆脱了记忆错误吗?你想解决什么问题?您看到测试用例中表现出的行为有几个原因:
小心-分配给进程的内存量与用于对象的内存量不同。大多数进程在分配给操作系统后不会将内存返回操作系统,因此即使垃圾收集器确实运行了,您也不一定会看到它通过分配给进程的总内存反映出来。在Java命令行应用选项
-XX:+useConMarkSweepGC
,以使用并发收集器。否则,我认为HotSpot只会在分配时触发集合。使用HTOP来衡量java任务的内存使用情况肯定是错误的,您需要使用探查器-如果您使用JDK 1.6或更高版本,那么VisualVM会随JDKWell一起提供,我使用HTOP是因为我对程序使用的实际内存感兴趣。但我想我明白了,也许Java不是完成这种alloc/free作业的最佳工具,如果您事先知道需要多少内存,那么只需将Java的最大堆限制在该大小即可。这将迫使GC更加雄心勃勃地回收内存。如果堆上有可回收的内存,您完全可以肯定GC不会允许出现内存不足的情况。这实际上是不推荐的。您可以用它暂停整个VM几秒钟。实际上,JVM决定何时为这个调用提供服务。垃圾收集器在被调用时被调用不是强制性的。所以从某种意义上说它是安全的。但我同意这是一种糟糕的编程实践。@user1559260这不是强制性的,但除非您指定-XX:+ExplicitGCInvokesConcurrent
,否则HotSpot会在调用gc()
@user1559260时停止所有线程。您错了。Javadoc明确指出,“当控件从方法调用返回时,虚拟机已尽最大努力回收所有丢弃的对象。”这是一个同步调用。你的意思是当我在while循环中将所有引用设置为null时?我在循环结束时尝试调用System.gc()一次。没有什么。如果我每10公里循环一次,它为什么会有什么作用?
System.gc();