2012-10-09 76 views
0

在排除了JVM的一個在我們的生產環境掛着問題,我們遇到在於執行以下語句記錄奇怪的JVM線程掛起 - 建議排除故障?

logger.debug("Loaded ids as " + ids + "."); 

一個線程被懸掛在這一步驟是可運行的線程狀態。這裏的ids是一個Set。還有另一個線程通過倒計數鎖存器等待上述線程來完成其任務。該軟件需要線程轉儲每15分鐘和兩個線程的蹤跡看如下

Stack trace for [THREAD GROUP: Job_Executor] [THREAD NAME:main-Runner Thread][THREAD STATE: WAITING] 
    ...sun.misc.Unsafe.park(Native Method) 
    ...java.util.concurrent.locks.LockSupport.park(Unknown Source) 
    ...java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(Unknown Source) 
    ...java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(Unknown Source) 
    ...java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(Unknown Source) 
    ...java.util.concurrent.CountDownLatch.await(Unknown Source) 
    ...com.runner.MainRunner.stopThread(MainRunnerRunner.java:1334) 


Stack trace for [THREAD GROUP: Job_Executor] [THREAD NAME:task executor][THREAD STATE: RUNNABLE]  
    ...java.util.AbstractCollection.toString(Unknown Source)   
    ...java.lang.String.valueOf(Unknown Source)  
    ...java.lang.StringBuilder.append(Unknown Source)  
    ...com.runner.CriticalTaskExecutor.loadByIds(CriticalTaskExecutor.java:143) 

此JVM得到了掛了近24小時,最後我們不得不殺死它往前走。線程轉儲表明在RUNNABLE狀態下有43個線程,包括上述線程。

上述線程在RUNNABLE狀態下執行collection.toString()24小時的原因是什麼?

關於如何進行的任何建議?

+3

你能告訴我們'的toString()'方法?任何延遲加載休眠字段或其他複雜? – Gray

+0

我會以此爲忠告。感謝您指出。 –

回答

0

這取決於被調用的方法toString()。當String的構建對於堆太大時,我見過AbstractCollection.toString。否則,問題可能出現在集合中對象的toString

爲了弄清楚它是哪一個,需要更多的堆棧轉儲(大約10個)。卡住的螺紋通常可能在導致問題的toString中。

作爲速戰速決,與

logger.debug("Loaded ids as {}.", ids); 

更換

logger.debug("Loaded ids as " + ids + "."); 

(假設你正在使用SLF4J,否則查找適當的方式做你的框架參數記錄)。

如果未啓用調試,則會跳過toString。

+0

這是如何解決'toString()'方法的問題? – Gray

+1

@格雷它沒有。但他們說這個問題是在生產中。 'toString'主要面向開發人員,通常不應該在生產IMHO中調用。 – artbristol

+0

真的嗎? ''toString()'在我們的環境中被所有的時間調用生產日誌。在渲染視圖時,Web應用程序在容器對象的每個地方調用'toString()'。 – Gray

1

可能是什麼原因,上述線程在RUNNABLE狀態24個小時,只是在執行collection.toString()?

您尚未提供足夠的信息來診斷問題。我只會挑戰你不要假設這裏發生了JVM問題。

如果我們看AbstractCollection.toString()方法的來源,我們會看到它遍歷集合並大致吐出「[item0,item1,item2]」。調用每個item.toString()方法來顯示該項目。

如果應用程序掛起在集合toString()那麼我的猜測是集合上的迭代器存在一些問題。如果你的應用程序正在旋轉,你可以告訴它 - 使用接近100%的CPU。 Set上的hasNext()方法總是返回true

如果應用程序掛在item.toString()的內部,那麼我會確保您的項目只顯示簡單的字段。請注意,如果訪問的字段使得RPC調用像延遲加載的ORM包裝字段一樣。

如果你提供有關問題的Set詳細信息,並顯示id.toString()代碼,我們可以幫助更多。

現在聽起來這是一套Integer對象。不知道爲什麼這會掛起你的應用程序。這裏有一些其他的想法:

  • 你是否以非同步方式訪問這個集合?多個線程是否可以對集合進行更改,以使其已損壞,從而導致其迭代器旋轉?您可以嘗試將其包裝在Collections.synchronizedSet(...)中。
  • 任何機會Set巨大。你被淘汰的內存中運行密切和程序是顛簸?這不會掛起你的應用程序,但只是慢慢爬行。你會開始看到內存異常。
  • 是否有任何機會,toString()被稱爲一遍又一遍?不過,我認爲你會在日誌中看到。
+0

感謝您的輸入。基礎集合是一個HashSet 。只是爲了讓我明白,如果代碼試圖對一個延遲加載的集合進行RPC調用,那麼堆棧跟蹤是否會指示?我的意思是不會顯示試圖進行數據庫調用的hibernate代碼的痕跡? –

+0

你會這樣想,是@安迪。我只是看不到一個'HashSet'懸掛任何東西,所以假設有其他事情正在進行。 – Gray

+0

AHA !! @AndyDufresne你正在同步這個集合?多線程以非同步的方式寫入此集合並破壞它以使某些東西在旋轉的任何機會? – Gray