我有一个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的。
答案 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
传递给ZipOutputStream
或DeflaterOutputStream
,则您有责任在Deflater上调用end()
。)
GC在您的情况下提供的帮助有限,因为必须取消引用流并最终确定。这可能需要多次GC扫描。我experienced与Jetty有类似的问题,并提出修复它。
答案 2 :(得分:1)
我确实遇到了另一种使用方式的问题。
我找到的解决方案如下:
很可能你的对象在另一个对象中被“隐藏 - 内部引用”,使用调试器并使用它“展开”所有对象。
当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