一如既往,一个冗长的问题描述。
我们目前正在对我们的产品进行压力测试 - 现在我们面临一个奇怪的问题。一到两个小时后,堆空间开始增长,应用程序稍后会死。
对应用程序进行概要分析会显示大量的Finalizer对象,从而填充堆。好吧,我们认为“可能是一个奇怪的终结器线程减慢”问题,并审查了减少需要最终确定的对象的数量(在这种情况下为JNA本机句柄)。无论如何都是好主意,减少了成千上万的新物......
接下来的测试显示了相同的模式,仅在一小时后并没有那么陡峭。这次Finalizers起源于在测试平台中大量使用的FileInput-和FileOutput流。所有资源都已关闭,但终结器不再清理。
我不知道为什么在1或2小时后(没有例外),FinalizerThread似乎突然停止工作。如果我们在一些线程中手动强制执行System.runFinalization(),则分析器会显示清除终结器。立即恢复测试会导致终结器的新堆分配。
FinalizerThread仍在那里,询问jConsole他是在等待。
修改
首先,使用HeapAnalyzer检查堆没有发现任何新的/奇怪的。 HeapAnalyzer有一些不错的功能,但我起初遇到了困难。我使用jProfiler,它附带了很好的堆检测工具,并将继续使用它。
也许我错过了HeapAnalyzer中的一些杀手级功能?
其次,今天我们使用调试连接而不是分析器来设置测试 - 系统现在稳定了将近5个小时。这似乎是一个非常奇怪的组合,包括太多的终结器(在第一次审查中已经减少),分析器和VM GC策略。由于目前一切运行良好,没有真正的见解......
感谢您到目前为止的输入 - 也许您保持关注和感兴趣(现在您可能有更多理由相信我们不会谈论简单的编程错误)。
答案 0 :(得分:3)
我想用当前状态的摘要来结束这个问题。
最后一次测试现在超过60小时没有任何问题。这导致我们得出以下总结/结论:
管理终结器的其他策略例如在http://cleversoft.wordpress.com/2011/05/14/out-of-memory-exception-from-finalizer-object-overflow/中讨论(除了不过分聪明的“不使用终结器”......)。
感谢您的所有输入。
答案 1 :(得分:1)
难以针对您的困境给出具体答案,但需要通过IBM的HeapAnalyzer进行堆转储并运行它。在http://www.ibm.com/developerworks搜索"堆分析器(直接链接不断变化)。似乎终结者线程突然停止工作"如果你没有最终确定。
答案 2 :(得分:1)
终结器有可能被阻止,但我不知道它是如何死的。
如果你有很多FileInputStream和FileOutputStream finalize()方法,这表明你没有正确关闭你的文件。确保这些流始终在finally块中关闭或使用Java 7的ARM。 (自动资源管理)
jConsole他正在等待。
要等待它必须等待一个物体。
答案 3 :(得分:1)
FileInputStream和FileOutputStream的finalize()方法都有相同的注释:
. . .
/*
* Finalizer should not release the FileDescriptor if another
* stream is still using it. If the user directly invokes
* close() then the FileDescriptor is also released.
*/
runningFinalize.set(Boolean.TRUE);
. . .
这意味着您的Finalizer可能正在等待流发布。这意味着,正如上面提到的Joop Eggen所说,当关闭其中一个流时,你的应用可能会做坏事。
答案 4 :(得分:0)
我的猜测:它是你自己的流(包装器)类中的覆盖关闭。由于流类通常是包装器并且委托给其他人,我可以想象这样一个嵌套的new A(new B(new C()))
可能会在关闭时导致一些错误的逻辑。你应该寻找两次关闭,委托结束。也许还有一些被遗忘的关闭(靠近错误的物体?)。
答案 5 :(得分:0)
随着堆缓慢增长,当Java垃圾收集器尝试在低内存情况下进行垃圾收集时,它可能会耗尽内存。尝试使用-XX:+UseConcMarkSweepGC启用并发标记和清除垃圾回收,并查看问题是否消失。