对 Java 内存泄漏进行故障排除:完成?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7644556/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 20:49:34  来源:igfitidea点击:

Troubleshooting a java memory leak: finalization?

javamemory-leaksfinalizer

提问by Rom1

I have a misbehaving application that seems to leak. After a brief profiler investigation, most memory (80%) is held by java.lang.ref.Finalizerinstances. I suspect that finalizers fail to run.

我有一个行为不端的应用程序似乎泄漏了。经过简短的分析器调查后,大多数内存 (80%) 由java.lang.ref.Finalizer实例持有。我怀疑终结器无法运行。

A common cause of this seems to be exceptions thrown from the finalizer. However, the javadoc for the finalizemethod of the Objectclass (see herefor instance) seems to contradict itself: it states

造成这种情况的一个常见原因似乎是终结器抛出的异常。但是,该类的finalize方法的 javadoc Object(例如参见此处)似乎自相矛盾:它指出

If an uncaught exception is thrown by the finalize method, the exception is ignored and finalization of that object terminates.

如果 finalize 方法抛出未捕获的异常,则忽略该异常并终止该对象的终结。

but later, it also states that

但后来,它也指出

Any exception thrown by the finalize method causes the finalization of this object to be halted, but is otherwise ignored.

finalize 方法抛出的任何异常都会导致此对象的终止被暂停,但否则会被忽略。

What should I believe (i.e., is finalization halted or not?), and do you have any tips on how to investigate such apparent leaks?

我应该相信什么(即最终确定是否停止?),您是否有任何关于如何调查此类明显泄漏的提示?

Thanks

谢谢

采纳答案by Phil Harvey

My first step would be to establish whether this is a genuine memory leak or not.

我的第一步是确定这是否是真正的内存泄漏。

The points raised in the previous answers all relate to the speedat which objects are collected, not the question of whether your objects are collected at all. Only the latter is a genuine memory leak.

前面回答中提到的点都与收集对象的速度有关,而不是您的对象是否收集的问题。只有后者才是真正的内存泄漏。

We had a similar predicament on my project, and ran the application in "slow motion" mode to figure out if we had a real leak. We were able to do this by slowing down the stream of input data.

我们在我的项目中遇到了类似的困境,并以“慢动作”模式运行应用程序,以确定我们是否有真正的泄漏。我们能够通过减慢输入数据流来做到这一点。

If the problem disappears when you run in "slow motion" mode, then the problem is probably one of the ones suggested in the previous answers, i.e. the Finalizer thread can't process the finalizer queue fast enough.

如果在“慢动作”模式下运行时问题消失,则问题可能是之前答案中建议的问题之一,即终结器线程无法足够快地处理终结器队列。

If that is the problem, it sounds like you might need to do some non-trivial refactoring as described in the pageBringer128 linked to, e.g.

如果这是问题所在,听起来您可能需要按照链接到的页面Bringer128 中所述进行一些重要的重构,例如

Now let's look at how to write classes that require postmortem cleanup so that their users do not encounter the problems previously outlined. The best way to do so is to split such classes into two -- one to hold the data that need postmortem cleanup, the other to hold everything else -- and define a finalizer only on the former

现在让我们看看如何编写需要事后清理的类,以便他们的用户不会遇到前面概述的问题。最好的方法是将这些类分成两个类——一个保存需要事后清理的数据,另一个保存其他所有内容——并仅在前者上定义终结器

回答by Bringer128

Both quotes say:

两个引文都说:

An exception will cause finalization of this object to be halted/terminated.

异常将导致该对象的终结被暂停/终止。

Both quotes also say:

这两句引文还说:

The uncaught exception is ignored (i.e. not logged or handled by the VM in any way)

未捕获的异常被忽略(即没有以任何方式被 VM 记录或处理)

So that answers the first half of your question. I don't know enough about Finalizers to give you advice on tracking down your memory leak though.

所以这回答了你问题的前半部分。不过,我对 Finalizer 的了解还不够,无法为您提供有关跟踪内存泄漏的建议。

EDIT: I found this pagewhich might be of use. It has advice such as setting fields to null manually in finalizers to allow the GC to reclaim them.

编辑:我发现这个页面可能有用。它有一些建议,例如在终结器中手动将字段设置为 null,以允许 GC 回收它们。

EDIT2: Some more interesting links and quotes:

EDIT2:一些更有趣的链接和引用:

From Anatomy of a Java Finalizer

来自Java Finalizer 的剖析

Finalizer threads are not given maximum priorities on systems. If a "Finalizer" thread cannot keep up with the rate at which higher priority threads cause finalizable objects to be queued, the finalizer queue will keep growing and cause the Java heap to fill up. Eventually the Java heap will get exhausted and a java.lang.OutOfMemoryError will be thrown.

终结器线程在系统上没有被赋予最大优先级。如果“终结器”线程跟不上更高优先级线程导致可终结对象排队的速度,终结器队列将继续增长并导致 Java 堆填满。最终,Java 堆将耗尽并抛出 java.lang.OutOfMemoryError。

and also

并且

it's not guaranteed that any objects that have a finalize() method are garbage collected.

不能保证任何具有 finalize() 方法的对象都会被垃圾收集。

EDIT3: Upon reading more of the Anatomy link, it appears that throwing exceptions in the Finalizer thread really slows it down, almost as much as calling Thread.yield(). You appear to be right that the Finalizer thread will eventually flag the object as able to be GC'd even if an exception is thrown. However, since the slowdown is significant it is possible that in your case the Finalizer thread is not keeping up with the object-creation-and-falling-out-of-scope rate.

EDIT3:在阅读更多 Anatomy 链接后,似乎在 Finalizer 线程中抛出异常确实会减慢它的速度,几乎与调用 Thread.yield() 一样多。您似乎是对的,即使抛出异常,Finalizer 线程最终也会将对象标记为可以进行 GC。但是,由于减速很重要,因此在您的情况下,Finalizer 线程可能跟不上对象创建和超出范围的速率。

回答by Manuel Selva

The item 7 of Effective Java second editionis: "Avoid finalizers". I strongly recommend you to read it. Here is an extract that may help you:

Effective Java 第二版的第 7 项是:“避免终结器”。我强烈建议你阅读它。以下是可能对您有所帮助的摘录:

"Explicit termination methods are typically used in combination with try-finally construct to ensure termination"

“显式终止方法通常与 try-finally 构造结合使用以确保终止”

回答by leef

I have same issue with you (below picture). For our case, it because an object has wait(0)in its finalize and it never get notified, which block the java.lang.ref.Finalizer$FinalizerThread. More reference

我和你有同样的问题(下图)。对于我们的例子,这是因为一个对象wait(0)在它的 finalize 中并且它永远不会得到通知,这阻塞了 java.lang.ref.Finalizer$FinalizerThread。更多参考

objects retained by Finalizer

终结器保留的对象

回答by samuel.song

i have once see a similar problem, that is the finalizer thread can not catch up with the rate of generating finalizable objects.

我曾经看到过一个类似的问题,就是finalizer线程跟不上生成finalizable对象的速度。

my solution is the make a closed loop control, by use the MemoryMXBean .getObjectPendingFinalizationCount(), a PD( proportinal and diffrential) control algo to control the speed we generate the finalizable objects, since we have a single entry to create it, just sleep number of seconds with the result of pd algo. it works well, though you need to tune the paramter for pd algo.

我的解决方案是进行闭环控制,通过使用 MemoryMXBean .getObjectPendingFinalizationCount(),一个 PD(比例和差分)控制算法来控制我们生成可终结对象的速度,因为我们只有一个条目来创建它,只需睡眠pd 算法结果的秒数。它运行良好,但您需要调整 pd 算法的参数。

hope it helps.

希望能帮助到你。