为什么垃圾回收器没有清除我的对象?

7
我有一个Java程序,它不断调用java.util.zip来压缩/解压数据。它在几秒钟内就会用完内存。我使用jmap生成了一个内存转储文件,并使用jhat查看它。
最终器总结显示待终结的实例总数:0。如果我理解正确,我没有任何对象符合以下条件:(1)具有finalize()方法,(2)被GC标记,(3)正在等待终结。这看起来很好。
当我查看特定对象时,对该对象的唯一引用是一个java.lang.ref.Finalizer。对于每个具有finalize()方法的对象,都将创建一个Finalizer对象,无论该对象是否被GC。因此,似乎没有任何东西阻止这个Deflater对象被GC。

位于 0x7f4aeb7a35d0 的对象

java.util.zip.Deflater@0x7f4aeb7a35d0 的实例(51字节)

对此对象的引用:

java.lang.ref.Finalizer@0x7f4aeb8607c8(64字节):字段referent

该程序在运行时通过System.in.read()暂停。内存使用量在一段时间后不会下降。
更新:
我应该澄清一下。内存转储文件显示许多对象未被GC,但没有其他对象(除Finalizer对象外)引用它们。我正在试图找出它们为什么没有被GC。

@dashrb 我的代码中没有使用Deflater。我正在使用Apache Thrift,它使用Deflater。 Deflater不在作用域内,因为“显示根集的所有成员”仅显示对Deflater类的1个引用,但未显示实例。 - woodings
1
实际上,你的内存不足并且没有被 GC 标记的对象是 不好 的。这意味着你的代码(或者你使用的某个库的代码)正在保留对对象的引用,因此 GC 无法收集它们。 - Ted Hopp
如果您使用jmap打印对象分配的直方图,那么可能会显示哪些对象正在消耗内存,并为您提供下一步查找的线索。这里有一篇关于使用开源工具跟踪内存泄漏的好文章(链接:http://www.infoq.com/articles/java-profiling-with-open-source)。 - Ted Hopp
为什么不使用内存分析来查看到底有哪些对象是活着的,以及谁在引用谁? - NPE
你可以尝试使用更加用户友好的工具来理解内存转储... Eclipse MAT 是一个不错的选择:http://www.eclipse.org/mat/ - Flavio
显示剩余4条评论
5个回答

5
您确定已经关闭了流并在压缩器上调用了end吗?如果这是一个您已经尝试过的简单建议,我很抱歉,但是有很多关于使用Deflater时出现内存泄漏的投诉,例如:

根本原因似乎是收集器无法跟上应用程序需要处理的本地元素内存使用情况。这也可以解释您在进行剖析时所看到的行为:内存已准备好被回收,但回收速度不够快。

由于您表示没有直接使用Deflator而是通过Apache Thrift,因此请尝试确定该库中负责结束压缩器的方法,并确保您已调用该方法。


1
基本问题在于您没有从C堆中释放对象。java.util.zip中的许多类使用Deflater。Deflater维护对C堆中数据的引用。您的代码可能没有在ZipOutputStream或DeflaterOutputStream上调用close(),或者没有在Deflater上调用end()。
(如果您将自己的Deflater传递给ZipOutputStream或DeflaterOutputStream,则需要负责在Deflater上调用end()。)
在您的情况下,GC的帮助有限,因为流必须被取消引用并最终完成。这可能需要多次GC扫描。我曾经在Jetty中遇到过类似的问题,并提出了一个修复方法。

1

补充Marian-Daniel Craciunescu的回答

我曾经遇到过另一种类型的问题。

我找到的解决方案如下:

  • 将对象放入地图或其他可以轻松丢弃其引用的位置
  • 同时将对象放入WeakReference中以供使用
  • 像平常一样使用您的引用
  • 从不再使用的地图中删除引用

注意继承引用

您的对象很可能被“隐藏-内部引用”在另一个对象中,请使用调试器并“展开”所有使用它的对象。

您永远不会知道GC何时运行,也不会知道它将处理什么(除了正在使用的对象)。

有用的链接

如果尚未完成,您应该阅读关于WeakReferences的这篇文章:Understanding Java's Reference classes: SoftReference, WeakReference, and PhantomReference


0
首先,在考虑内存泄漏之前,我们应该尝试了解所需的内存是否符合您正在进行的处理的正常要求。JVM可用内存大小是多少,即-XmX。如果增加内存大小或减小正在处理的文件大小是否有效?

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接