2011-11-08 47 views
11

我在構建服務器上存在間歇性問題,構建中的某個Java進程無法終止,並且似乎永遠持續運行(使用100%的CPU)(我已經看到它在整個週末運行了2天以上通常需要大約10分鐘)。似乎是阻止這一進程的唯一途徑。這個Java進程爲什麼沒有終止?

我已經試過在進程上調用kill -QUIT pid,但它似乎沒有產生任何堆棧跟蹤到STDOUT(也許它沒有響應信號?)。沒有-F強制選項的jstack似乎無法連接到正在運行的JVM,但使用強制選項時,它確實會生成下面的輸出。

不幸的是,即使有堆棧跟蹤,我也看不到有任何明顯的路徑需要進一步調查。

據我可以告訴它顯示兩個運行Object.wait的'BLOCKED'線程(它們的堆棧似乎只包含核心Java代碼,沒有我們的),第三個是'IN_VM'沒有堆棧輸出。

我應該採取什麼措施來收集有關問題原因的更多信息(或者更好,但我該如何解決問題)?

 
$ /opt/jdk1.6.0_29/bin/jstack -l -F 5546 
Attaching to process ID 5546, please wait... 
Debugger attached successfully. 
Server compiler detected. 
JVM version is 20.4-b02 
Deadlock Detection: 

No deadlocks found. 

Finding object size using Printezis bits and skipping over... 
Thread 5555: (state = BLOCKED) 

Locked ownable synchronizers: 
    - None 

Thread 5554: (state = BLOCKED) 
- java.lang.Object.wait(long) @bci=0 (Interpreted frame) 
- java.lang.ref.ReferenceQueue.remove(long) @bci=44, line=118 (Interpreted frame) 
- java.lang.ref.ReferenceQueue.remove() @bci=2, line=134 (Interpreted frame) 
- java.lang.ref.Finalizer$FinalizerThread.run() @bci=3, line=159 (Interpreted frame) 

Locked ownable synchronizers: 
    - None 

Thread 5553: (state = BLOCKED) 
- java.lang.Object.wait(long) @bci=0 (Interpreted frame) 
- java.lang.Object.wait() @bci=2, line=485 (Interpreted frame) 
- java.lang.ref.Reference$ReferenceHandler.run() @bci=46, line=116 (Interpreted frame) 

Locked ownable synchronizers: 
    - None 

Thread 5548: (state = IN_VM) 

Locked ownable synchronizers: 
    - None 

(Java版本1.6.0更新29,科學運行Linux 6.0版)

更新:

運行strace -f -p 894產生的一個看似層出不窮......

[pid 900] sched_yield()    = 0 
[pid 900] sched_yield()    = 0 
... 

然後當Ctrl-Cd

Process 894 detached 
... 
Process 900 detached 
... 
Process 909 detached 

jmap -histo 894沒有連接,但jmap -F -histo 894回報......

 
Attaching to process ID 894, please wait... 
Debugger attached successfully. 
Server compiler detected. 
JVM version is 20.4-b02 
Iterating over heap. This may take a while... 
Finding object size using Printezis bits and skipping over... 
Finding object size using Printezis bits and skipping over... 
Object Histogram: 

num  #instances #bytes Class description 
-------------------------------------------------------------------------- 
1:  11356 1551744 * MethodKlass 
2:  11356 1435944 * ConstMethodKlass 
3:  914 973488 * ConstantPoolKlass 
4:  6717 849032 char[] 
5:  16987 820072 * SymbolKlass 
6:  2305 686048 byte[] 
7:  914 672792 * InstanceKlassKlass 
8:  857 650312 * ConstantPoolCacheKlass 
9:  5243 167776 java.lang.String 
10:  1046 108784 java.lang.Class 
11:  1400 87576 short[] 
12:  1556 84040 * System ObjArray 
13:  1037 64584 int[] 
14:  103 60152 * ObjArrayKlassKlass 
15:  622 54736 java.lang.reflect.Method 
16:  1102 49760 java.lang.Object[] 
17:  937 37480 java.util.TreeMap$Entry 
18:  332 27960 java.util.HashMap$Entry[] 
19:  579 27792 java.nio.HeapByteBuffer 
20:  578 27744 java.nio.HeapCharBuffer 
21:  1021 24504 java.lang.StringBuilder 
22:  1158 24176 java.lang.Class[] 
23:  721 23072 java.util.HashMap$Entry 
24:  434 20832 java.util.TreeMap 
25:  689 18936 java.lang.String[] 
26:  238 17440 java.lang.reflect.Method[] 
27:  29 16800 * MethodDataKlass 
28:  204 14688 java.lang.reflect.Field 
29:  330 13200 java.util.LinkedHashMap$Entry 
30:  264 12672 java.util.HashMap 
... 
585:  1 16 java.util.LinkedHashSet 
586:  1 16 sun.rmi.runtime.NewThreadAction$2 
587:  1 16 java.util.Hashtable$EmptyIterator 
588:  1 16 java.util.Collections$EmptySet 
Total :  79700 8894800 
Heap traversal took 1.288 seconds. 
+0

您可以嘗試在運行服務器的控制檯上按[CTRL] + [SYSREQ]。這會給你一個線程轉儲,它會像獲取的那樣冗長。 – JimmyB

回答

1

螺紋5554可能表明你有很多與finalize方法,對象,和/或某些問題有finalize方法。看這個可能是值得的。

我對jstack並不熟悉,但它看起來像輸出的信息更少,我更熟悉的線程轉儲。嘗試獲取線程轉儲可能很有用:kill -QUIT java_pid。請注意,轉儲轉到標準輸出可能是控制檯或記錄文件,具體取決於您的設置。

如果很難確定標準輸出指向哪裏,並且假定它正在進入一個文件,那麼在最近的修改時間內可以使用find來標識候選文件。這暗示了在註釋this blog post

你可以運行在您的根目錄中找到[2]命令,並找出 在過去x秒改變。我通常使用find來幫助我 訪問最近10分鐘內發生更改的所有日誌,例如:find /var/tomcat -mmin -3 -print(打印出所有在 /var/tomcat下修改的文件最後3分鐘)。

請注意,如果您正在使用-Xrs運行的JVM,這意味着SIGQUIT信號處理程序將不會被安裝,您將無法使用請求線程轉儲的意思。

+0

5554是終結者,應該停放,除非有確定的東西。它不應該阻止這個過程終止。殺-QUIT是一個非常好的主意,因爲它可以幫助你弄清楚5555是怎麼回事,看起來更可能是罪魁禍首。 – philwb

+0

下次發生問題時,我會嘗試'kill -QUIT'並查看是否提供了更多信息,謝謝。 我想可能會有一些自定義的finalisers,但他們應該做的只是關閉打開的文件。我想這是快速和相當安全的,但也許不是... –

+0

我認爲@philwb將是正確的。終結者可能沒有錯 - 終結者線程正在等待某事做,而不是在工作時被阻塞。 – sudocode

2

這可能是由內存不足也引起。我要做兩件事情:

  • 由addingJVM內存不足啓用自動堆轉儲參數

    -XX:+ HeapDumpOnOutOfMemoryError XX:HeapDumpPath =/tmp目錄

  • 嘗試連接到與您的JConsole JVM並看看是否有任何不尋常的模式

+0

不幸的是,jconsole似乎沒有連接到它(如果我遠程嘗試,只是超時,如果我從服務器運行它,相關的PID在列表中灰顯)。我將看看我可以做些什麼來將這些參數傳遞給正確的JVM調用。 –

2

我會懷疑內存問題。您可能需要使用jstat觀察進程,並在需要殺死進程的時間周圍使用jmap進行堆轉儲。查看jstat是否指示連續的GC。另外,您可能需要檢查一般系統的運行狀況(打開文件描述符,網絡等)。記憶將是最簡單的,所以我強烈建議從它開始。

+0

不幸的是,jstat給了我'無法與目標同步'的消息。 jmap似乎能夠產生一些信息(我會更新上面的問題)。 –

+0

除了上面的直方圖之外,我似乎可以用'jmap -F -dump:format = b,file = heap.bin 894'獲得一堆堆,但我還不確定如何處理它。 –

+0

你可以使用eclipse MAT來查看堆轉儲。尋找泄漏嫌疑人。然而,很奇怪你無法使用jstat。你使用了什麼命令? – aishwarya

3

您總是可以通過strace -f -p pid來查看Java進程正在做什麼。從它的外觀(你不能讓一個jstack沒有-F和螺紋5548顯示沒有調用堆棧,並IN_VM),它看起來像螺紋5548正在做過多的東西,或者可能是在某些無限循環。

+0

正在運行'strace -f -p 894'我收到了一堆說''pid 900] sched_yield()= 0'的線......有趣... –

+0

@MattSheppard:從這一點來說,我會遵循bestsss的建議,得到一些回溯。如果你的系統有'pstack',只需執行'pstack '。否則,你必須執行'gdb/path/to/java ',並從gdb'bt'和'quit'執行。 – ninjalj

+0

我會在下次發生時嘗試。 –

1

我遇到了類似的問題,我的JBOSS jvm得到了一個無限循環,最終得到了OutOfMemory,我不能殺死這個進程而是殺死-9。我懷疑大多數情況下的內存問題。

2

當進程正常運行時通過jstack -F(-F必須存在,它產生不同於快速jstack的快照)時創建快照。線程號不是Thread.id,而是系統號。 5548似乎是在Finalizer和RefCounter之前創建的(它們不是問題的根源),因此它應該是GC線程或某個編譯器。

100%,可能意味着在顯示器的一些bug。 Java(熱點)監視器使用非常簡單的自旋鎖定機制來確保所有權。

和當然,附加一個調試器 - GDB檢查到底在哪過程中一直堅持。

0

這裏有一些工具,你可以用本地化進程的一部分消耗CPU:

  • perf/oprofile,尤其是opannotate - 偉大的看到什麼是地獄代碼消耗週期
  • stracegstack/gdb(正如其他人所提到的)
  • systemtap功能非常強大,但與基於ptrace的工具的某些相同方式受到限制(如果您的問題不涉及sysc所有這些都不那麼有效)。