在我们的服务器上,我们开始遇到OutOfMemoryError
. 我们使用 Eclipse Memory Analysis 分析了堆转储,发现有许多对象被用来做终结处理(大约是堆的 2/3):
我们发现,它可能是一些 finalize() 方法阻塞。我发现了几个关于这个问题的错误报告(这里或这里),它总是在终结器线程堆栈中表现出来,它在某个地方被阻塞。但在我们的例子中,这个线程正在等待:
"Finalizer" daemon prio=10 tid=0x43e1e000 nid=0x3ff in Object.wait() [0x43dfe000]
java.lang.Thread.State: WAITING (on object monitor)
at java.lang.Object.wait(Native Method)
- waiting on <0x4fe053e8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:133)
- locked <0x4fe053e8> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:149)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:189)
编辑:
然后我们尝试添加-XX:+UseConcMarkSweepGC
,但没有成功,只是OutOfMemoryError
s 的频率减少了,所以我们首先认为它有帮助。
最后,我们怀疑是 JVM 的 bug,从 OpenJDK 1.6.0_30 升级到 Oracle JDK 1.7.0_51,问题就消失了(至少看起来是这样,在过去的 4 个小时里,使用的堆没有增长)。我们不记得 finalize 方法有任何变化,也没有升级任何库,在那段时间里只有很小的发展。该问题不会在我们的测试服务器上重现,配置相同,只是它是 64 位 JVM,而生产服务器是 32 位。
Finalizer
问题是:对象未最终确定和线程等待下一个对象的原因可能是什么?我们是否正确分析了堆转储?
感谢所有的答案。