7

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

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

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

0x7f4aeb7a35d0 处的对象

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

对该对象的引用:

java.lang.ref.Finalizer@0x7f4aeb8607c8 (64 bytes) : 字段引用

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

更新:

我应该说清楚。内存转储显示许多对象没有经过 GC,但没有其他对象(终结器对象除外)引用它们。我试图找出为什么他们没有被 GC'ed。

4

5 回答 5

5

您确定您关闭了流并end在 deflater 上调用了吗?如果这是您已经尝试过的简单建议,我很抱歉,但是Deflater在不立即调用end它时使用时有很多关于内存泄漏的投诉,例如:

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

由于您没有Deflator直接使用 a 而是通过 Apache Thrift 编写的,因此请尝试确定该库中的哪个方法负责结束 deflator,并确保您调用了该方法。

于 2012-11-25T11:29:30.910 回答
1

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

(如果您将自己的传递DeflaterZipOutputStreamor DeflaterOutputStream,则您有责任调用end()Deflater。)

GC 在您的情况下的帮助有限,因为必须取消引用并最终确定流。这可能需要多次 GC 扫描。我在 Jetty 上遇到了类似的问题,并提出了解决方案。

于 2012-11-26T01:45:30.240 回答
1

添加到 Marian-Daniel Craciunescu 的回答

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

我找到的解决方案如下:

  • 将对象放入地图或您可以轻松删除其引用的地方
  • 将对象放入WeakReference 以使用它
  • 照常使用您的参考资料
  • 从不再使用的地图中删除参考

小心继承的引用

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

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

有用的链接

您应该阅读(如果尚未完成)这篇关于 WeakReferences 的文章:了解 Java 的参考类:SoftReference、WeakReference 和 PhantomReference

于 2012-11-30T16:28:44.923 回答
0

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

于 2012-12-01T13:52:26.370 回答
-1

也许你应该为你的对象使用 Wea​​kReference。这样 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 -参考

于 2012-11-28T12:08:57.650 回答