2014-03-07 20 views
5

在我們的服務器上,我們開始遇到OutOfMemoryError問題。我們分析了堆轉儲使用Eclipse內存分析和發現,許多對象舉行做最後定稿(約堆的2/3):對象未完成,終結器線程無法執行任何操作

enter image description here

我們發現,這可能是一些的finalize( )方法阻塞。我發現了這個問題的幾個錯誤報告(herehere),並且它始終表現在Finalizer線程堆棧中,它在某處被阻塞。但是,在我們的例子中,這個線程在等待:

"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個小時中,使用的堆不會增長)。我們不記得定稿方法有什麼變化,我們也沒有升級任何圖書館,在那段時間只有小的發展。這個問題不會在我們的測試服務器上重現,具有相同的配置,只是它是64位JVM,而生產服務器是32位。

現在的問題是:什麼原因可能導致對象未完成並且Finalizer線程正在等待下一個對象?我們是否正確分析了堆轉儲?

感謝您的所有答案。

+0

你的終結者線程正在等待某個東西被終結(它在'ReferenceQueue.remove()'上被阻塞),這意味着沒有任何對象要被終結。你是怎麼得出這個結論是'finalize()'方法阻塞的?你是否在代碼中積極使用'finalize()'? – Kayaman

+0

@Kayaman通過分析堆轉儲,請參見圖片 – Oliv

回答

1

我們認爲它與OpenJDK版本1.6.0_30有關。升級到Oracle JDK 1.7.0_51後,問題消失了。它可能出現在openJDK自動更新後,但我們無法證實這一點。我們找不到相關的錯誤報告。

0

Finalizer線程具有低優先級,因此將花費大量時間WAITING而不是最終確定。我不會從該堆棧跟蹤中得出結論:該線程被阻塞;它只是放棄了對其他線程的控制權。相反,您可能會引入pathological number of objects into the finalizer queue,而JVM根本無法跟上。

不幸的是有太多可能的解釋,爲什麼這個行爲在版本之間改變以確定一個確切的原因,但這裏有一個可能的解釋。甲骨文的Java 7有一個新的,更高效的garbage collector。可以想象,減輕GC負載意味着終結器隊列在處理器上獲得更多時間,因此能夠跟上添加到其中的對象的數量。

但是不管底層原因,正確的解決方案是減少終結器的使用。除非在非常有限的情況下,它們會引入比解決更多的問題,而不僅僅是GC和內存開銷。如果你有有史以來發現自己正在調查的對象正在等待finalization清理,你正在構造太多的可終結對象。

+0

這可能並非如此,因爲該服務器的平均CPU使用率大約爲5%,所以終結器有足夠的時間來完成它的工作。 – Oliv

相關問題