我创建了一个带有一系列子项的trie树。删除单词时,我将子项设置为null,我假设删除该节点(delete是相对术语)。我知道null不会删除子节点,只需将其设置为null,这在使用大量单词时会导致溢出堆。
在linux上运行top,我可以很快看到我的内存使用量达到1gb,但是如果我在删除后强制进行垃圾收集(Runtime.gc()),则内存使用率将达到50mb并且永远不会高于此值。据我所知,java默认情况下会在堆溢出发生之前运行垃圾收集,但是我无法看到这种情况发生。
答案 0 :(得分:5)
(这个评论太长了)
与流行的看法相反,你 CAN 真的强迫用Java加入GC,但不使用 System.gc()完成。真正强制GC的方法是使用JVMTI的 ForceGarbageCollection()调用。不要问我更多,我在这里问了一个问题,没有人发现它很有趣(没有upvotes),也没有人能回答它,但JVMTI的 ForceGarbageCollection()是很多Java程序如IntelliJ,NetBeans的,VisualVM,Eclipse等。确实强制GC :
Java: How do you really force a GC using JVMTI's ForceGargabeCollection?
现在......您可能不想要这样做,您可能不想要使用“无保证”系统提示GC。 gc()电话。
你有多少话开始有问题?当您需要使用疯狂的单词数时,有非常紧凑的数据结构。您确定使用的是正确的数据结构吗?您确定没有泄漏吗?
答案 1 :(得分:3)
您是指未释放到操作系统的内存 - 即top
和类似程序显示Java进程需要1GB内存吗?即使Java的垃圾收集器从其堆中释放内存,它仍然可以保留内存,以便将来的分配不需要从操作系统请求更多内存。
要查看Java对象实际使用了多少堆空间,请使用VisualVM或类似的Java特定工具。如果您的计算机有大量内存,那么JVM将使用它(IIRC,特别是服务器VM被调整为保留更多内存),但您始终可以使用-Xmx
和其他JVM选项来限制它。
答案 2 :(得分:1)
好的,你得到java.lang.OutOfMemoryError: Java heap space
最有可能的是,Runtime.gc()
无济于事,因为如果可以的话,JVM已经做了一个gc。
这可能是内存泄漏。如果我是你,我会仔细检查我的代码,看看是否某些引用仍然存在。
所以孙子们不会被删除? 当我删除时,我只是设置它 子节点为null,但不是 孩子的孩子,但那些 孩子们没有被初始化, 只创建(Node [] children = new 节点[26]
如果你做children=null
,是的,整个数组应该是gc'd。前提是你没有提到某些东西。
但谁知道罪魁祸首是什么。它甚至可能不是这些“儿童”节点。您可能希望使用visualVm并找出正在累积的对象。您可以使用更复杂的工具,如JProfiler,并检查引用等,但如果您只是构建一个trie,我想更简单的方法是遍历您的代码并发现泄漏。
答案 3 :(得分:0)
分配给进程(即JVM)的内存不一定返回给Unix中的操作系统。因此,即使Java虚拟机可能已经完全垃圾收集了堆,但是进程大小可能保持不变。
通常情况下,这可能不会产生太大影响,因为未使用的堆将被分页并且不再被重新分页。查看ps -u
输出中虚拟大小(VSZ)和驻留集大小(RSS)之间的差异,区别在于换出的页数。
答案 4 :(得分:0)
只有在任何可访问对象的链接无法访问对象后,才会删除该对象。您是否仍然可以参考相关对象?
顺便说一下,Runtime.gc()
有时只是提示应该运行垃圾收集。