java 内存泄漏故障排除:终结?
我有一个行为不当的应用程序,似乎存在泄漏。经过简短的探查器调查后,大多数内存 (80%) 由 java.lang.ref.Finalizer
实例占用。我怀疑终结器无法运行。
造成这种情况的一个常见原因似乎是终结器抛出异常。但是,Object
类的 finalize
方法的 javadoc(请参阅 这里 例如)似乎自相矛盾:它指出
如果 Finalize 方法抛出未捕获的异常,则该异常将被忽略,并且该对象的终结将终止。
但后来,它还指出
finalize 方法抛出的任何异常都会导致该对象的终结终止,但会被忽略。
我应该相信什么(即最终确定是否已停止?),您对如何调查此类明显的泄漏有什么建议吗?
谢谢
I have a misbehaving application that seems to leak. After a brief profiler investigation, most memory (80%) is held by java.lang.ref.Finalizer
instances. I suspect that finalizers fail to run.
A common cause of this seems to be exceptions thrown from the finalizer. However, the javadoc for the finalize
method of the Object
class (see here for instance) seems to contradict itself: it states
If an uncaught exception is thrown by the finalize method, the exception is ignored and finalization of that object terminates.
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.
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
两句话都说:
这两句话还说:
这回答了您问题的前半部分。不过,我对终结器了解不够,无法为您提供跟踪内存泄漏的建议。
编辑:我发现此页面可能有用。它有一些建议,例如在终结器中手动将字段设置为 null,以允许 GC 回收它们。
EDIT2:一些更有趣的链接和引用:
来自 Java Finalizer 的剖析
还有
EDIT3:在阅读更多的 Anatomy 链接后,似乎在 Finalizer 线程中抛出异常确实会减慢速度,几乎与调用 Thread.yield() 一样慢。您似乎是对的,即使抛出异常,Finalizer 线程最终也会将对象标记为能够进行 GC。但是,由于速度减慢很明显,因此在您的情况下,终结器线程可能无法跟上对象创建和超出范围的速度。
Both quotes say:
Both quotes also say:
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.
EDIT: I found this page which might be of use. It has advice such as setting fields to null manually in finalizers to allow the GC to reclaim them.
EDIT2: Some more interesting links and quotes:
From Anatomy of a Java Finalizer
and also
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.
我的第一步是确定这是否是真正的内存泄漏。
前面的答案中提出的要点都与收集对象的速度有关,而不是您的对象是否被收集的问题。只有后者才是真正的内存泄漏。
我们在我的项目中遇到了类似的困境,并以“慢动作”模式运行应用程序来确定是否存在真正的泄漏。我们能够通过减慢输入数据流来做到这一点。
如果在“慢动作”模式下运行时问题消失,则问题可能是前面答案中建议的问题之一,即终结器线程无法足够快地处理终结器队列。
如果这是问题所在,那么听起来您可能需要进行一些重要的重构,如 页面 Bringer128 链接到,例如
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 speed at 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 page Bringer128 linked to, e.g.
《Effective》Java 第二版第 7 条是:“避免终结器”。我强烈建议您阅读它。以下摘录可能对您有帮助:
“显式终止方法通常与 try-finally 结构结合使用以确保终止”
The item 7 of Effective Java second edition is: "Avoid finalizers". I strongly recommend you to read it. Here is an extract that may help you:
"Explicit termination methods are typically used in combination with try-finally construct to ensure termination"
我和你有同样的问题(下图)。对于我们的例子,这是因为一个对象在其finalize中具有
wait(0)
并且它永远不会得到通知,这会阻塞java.lang.ref.Finalizer$FinalizerThread。更多参考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我曾经看到过类似的问题,那就是终结器线程无法跟上生成可终结对象的速度。
我的解决方案是创建一个闭环控制,通过使用 MemoryMXBean .getObjectPendingFinalizationCount(),一个 PD(比例和微分)控制算法来控制我们生成可终结对象的速度,因为我们有一个条目来创建它,只需睡眠pd 算法结果的秒数。它运行良好,但您需要调整 pd 算法的参数。
希望有帮助。
i have once see a similar problem, that is the finalizer thread can not catch up with the rate of generating finalizable objects.
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.
hope it helps.