为什么GC不收集我的物品?

时间:2012-11-21 18:54:14

标签: java memory-leaks garbage-collection jmap jhat

我有一个java程序,它一直调用java.util.zip来压缩/解压缩数据。它会在几秒钟内耗尽内存。 我有jmap的内存转储,我正在使用jhat查看。

终结器摘要显示Total instances pending finalization: 0。如果我理解正确,我没有任何对象(1)有finalize()方法,(2)已经被GC标记,(3)等待最终确定。这似乎很好。

当我查看特定对象时,对该对象的唯一引用是java.lang.ref.Finalizer。无论对象是否为GC,都会为每个具有finalize()方法的对象创建Finalizer对象。所以看起来没有什么能阻止这个Deflater对象成为GC。

  

对象位于0x7f4aeb7a35d0

     

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

     

对此对象的引用:

     

java.lang.ref.Finalizer@0x7f4aeb8607c8(64 bytes):field referent

该程序在System.in.read()的运行中暂停。一段时间后,内存使用率不会下降。

更新:

我应该说清楚。内存转储显示许多对象没有GC,但没有其他对象(Finalizer对象除外)引用它们。我试图找出他们为什么不是GC的。

5 个答案:

答案 0 :(得分:5)

您是否肯定关闭了流并在deflater上调用了end?如果这是一个你已经尝试过的简单建议,我很抱歉,但是当使用Deflater时没有立即调用end时,有很多关于内存泄漏的抱怨,例如:< / p>

根本原因显然是当涉及本机元素使用的内存时,收集器无法跟上应用程序。这也解释了您在分析时看到的行为:内存已准备好回收,但只是没有足够快地回收。

由于您写道,您不直接使用Deflator,而是通过Apache Thrift,尝试确定该库中哪个方法负责结束平减指数,并确保您调用该方法。

答案 1 :(得分:1)

基本问题是你没有从C堆中释放对象。 java.util.zip中的许多类都使用Deflater。 Deflater维护对C堆中数据的引用。 您的代码可能未在close()ZipOutputStream上调用DeflaterOutputStream ,或者在end()上未调用Deflater

(如果您将自己的Deflater传递给ZipOutputStreamDeflaterOutputStream,则您有责任在Deflater上调用end()。)

GC在您的情况下提供的帮助有限,因为必须取消引用流并最终确定。这可能需要多次GC扫描。我experienced与Jetty有类似的问题,并提出修复它。

答案 2 :(得分:1)

加入Marian-Daniel Craciunescu的回答

我确实遇到了另一种使用方式的问题。

我找到的解决方案如下:

  • 将对象放入地图或某个地方,您可以轻松删除其参考
  • 对象放入WeakReference中以便使用
  • 正常使用您的参考
  • 从地图中删除不再使用的参考

小心继承的引用

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

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

有用的链接

你应该阅读(如果还没有)这篇关于WeakReferences的帖子:Understanding Java's Reference classes: SoftReference, WeakReference, and PhantomReference

答案 3 :(得分:0)

首先,在考虑内存泄漏之前,我们应该尝试了解内存需求是否与正在进行的处理一样正常。 JVM可用的内存大小是多少,即-XmX。如果你增加内存的大小或减少正在处理的文件的大小确实有用吗?

答案 4 :(得分:-1)

也许你应该为你的对象使用WeakReference。这样GC可以很快地完成()你的对象

http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html http://weblogs.java.net/blog/2006/05/04/understanding-weak-references