16

更新:這看起來像是一個內存問題。一個3.8 GB的Hprof文件表明,當發生這種「阻塞」時,JVM正在傾銷它的堆。我們的運營團隊發現該網站沒有響應,拿走了堆棧跟蹤,然後關閉了該實例。我相信他們在堆轉儲完成之前關閉了該站點。日誌有沒有錯誤/異常/問題的證據 - 可能是因爲JVM在它可能產生錯誤消息之前被殺死。Java阻塞問題:爲什麼JVM會阻塞許多不同類/方法中的線程?

原問題 我們有最近的情況,應用程序出現 - 最終用戶 - 掛起。我們在重啓應用程序之前得到了一個堆棧跟蹤,並且我發現了一些令人驚訝的結果:527個線程,463個線程狀態爲BLOCKED。

過去 在過去阻塞的線程通常有這個問題: 1)一些明顯的瓶頸:如導致其他線程等待的某些數據庫記錄鎖定或文件系統鎖定問題。 2)所有阻塞的線程會阻塞在同一類/方法(例如JDBC或文件系統clases)

異常數據 在這種情況下,我看到堵塞的類/方法各種各樣,包括JVM內部類,JBoss的類,log4j的,等等,除了應用程序類(包括JDBC和Lucene電話)

問題 什麼會導致一個JVM阻止log4j.Hierarchy.getLogger,java.lang.reflect.Constructor中。的newInstance?很明顯,某些資源「很稀缺」,但哪些資源?

感謝

堆棧跟蹤摘錄

http-0.0.0.0-80-417" daemon prio=6 tid=0x000000000f6f1800 nid=0x1a00 waiting for monitor entry [0x000000002dd5d000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
       at sun.reflect.GeneratedConstructorAccessor68.newInstance(Unknown Source) 
       at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) 
       at java.lang.reflect.Constructor.newInstance(Constructor.java:513) 
       at java.lang.Class.newInstance0(Class.java:355) 
       at java.lang.Class.newInstance(Class.java:308) 
       at org.jboss.ejb.Container.createBeanClassInstance(Container.java:630) 

http-0.0.0.0-80-451" daemon prio=6 tid=0x000000000f184800 nid=0x14d4 waiting for monitor entry [0x000000003843d000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
       at java.lang.Class.getDeclaredMethods0(Native Method) 
       at java.lang.Class.privateGetDeclaredMethods(Class.java:2427) 
       at java.lang.Class.getMethod0(Class.java:2670) 

"http-0.0.0.0-80-449" daemon prio=6 tid=0x000000000f17d000 nid=0x2240 waiting for monitor entry [0x000000002fa5f000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
       at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.register(Http11Protocol.java:638) 
       - waiting to lock <0x00000007067515e8> (a org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler) 
       at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.createProcessor(Http11Protocol.java:630) 


"http-0.0.0.0-80-439" daemon prio=6 tid=0x000000000f701800 nid=0x1ed8 waiting for monitor entry [0x000000002f35b000] 
    java.lang.Thread.State: BLOCKED (on object monitor) 
       at org.apache.log4j.Hierarchy.getLogger(Hierarchy.java:261) 
       at org.apache.log4j.Hierarchy.getLogger(Hierarchy.java:242) 
       at org.apache.log4j.LogManager.getLogger(LogManager.java:198) 
+1

如何在GC日誌看? – 2010-10-25 16:58:06

回答

16

這些順序我會嘗試他們,根據收集的證據大致列出:

  • 你看過GC行爲?你有沒有受到內存壓力?這可能導致newInstance()和其他一些上述被阻止。用-XX:+PrintGCDetails -XX:+PrintGCTimeStamps -verbose:gc運行虛擬機並記錄輸出。在故障/鎖定時間附近是否看到過多的GC時間?
    • 是條件可重複?如果是這樣,請嘗試在JVM中改變堆大小(-Xmx)並查看行爲是否有實質性改變。如果是這樣,請查找內存泄漏或正確調整應用程序的堆大小。
    • 如果以前是困難的,並且您在應該時未收到OutOfMemoryError,則可以調諧GC可調參數...請參閱JDK6.0 XX optionsJDK6.0 GC Tuning Whitepaper。請特別注意-XX:+UseGCOverheadLimit-XX:+GCTimeLimit及相關選項。 (注意,這些有據可查的,但可能是有用的...)
  • 也許會有一個僵局?只有堆棧跟蹤摘錄,無法在這裏確定。在監視器狀態中查找線程被阻塞的週期(與他們持有的線程相比)。我相信jconsole能爲你做到這一點...(yep, under the threads tab, "detect deadlocks"
  • 嘗試做一些重複蹤跡,尋找什麼樣的變化與什麼保持不變...
  • 執行取證......每個堆棧輸入「BLOCKED」,查找特定的代碼行並確定是否有顯示器。如果有實際的監視器採集,應該很容易識別限制資源。然而,你的一些線程可能會顯示阻塞沒有可用的透明顯示器,這些都將是棘手的...
+0

看起來我們有一個OutOfMemoryException異常的,而且JVM已經開始拋售,其存儲器(即HeapDumpOnOutOfMemoryError),但操作殺害了JVM它完成之前。日誌有沒有異常或內存溢出錯誤.... – user331465 2010-10-25 16:41:24

+0

@ user331465:是啊,它可能需要一些時間的OOM病情反而觸發OOM錯誤。請參閱有關UseGCOverheadLimit,GCTimeLimit,GCHeapFreeLimit JVM中的XX選項。大概這是你的問題的一部分 - 分配內存的線程被阻塞不是因爲鎖本身,而是因爲它們正在等待分配內存。 – andersoj 2010-10-25 16:45:17

+1

@ user331465:建議你修改你的問題,包括有關GC /內存問題的信息,因爲它的重點問題大增。 – andersoj 2010-10-25 16:55:24