AIX® ビジー・ハング
スレッド間でデッドロックが発生していない場合は、スレッドが正常に実行されない別の理由を考慮してください。
- 実行すべき処理が「通知される」のを、スレッドが「待機している」状態である。
- スレッドが明示的にスリープ状態を繰り返す。
- 入出力が実行されるようになるまで、スレッドが入出力呼び出しを待機している。
スレッドが (例えば、ソケットで) 入出力を待機しているという 3 つ目の理由の場合は、さらに調査が必要です。 入出力のもう一方のプロセスが失敗しましたか? ネットワーク問題がありますか?
javadump ツールを使用してループを診断する方法については、 THREADSを参照してください。 javadump から問題を診断できない場合に、プロセスがプロセッサー・サイクルをまだ使用しているようであれば、無限ループに入ったか、あるいはパフォーマンスが非常に悪い状態です。 その場合は、ps -mp [process id] -o THREAD を使用して、特定のプロセス内の各スレッドをモニターし、CPU 時間を使用しているスレッドを判別することができます。 プロセスが無限ループに入った場合は、少数のスレッドで時間が使用される可能性があります。 例:
$ ps -mp 43824 -o THREAD
USER PID PPID TID ST CP PRI SC WCHAN F TT BND COMMAND
wsuser 43824 51762 - A 66 60 77 * 200001 pts/4 - java ...
- - - 4021 S 0 60 1 22c4d670 c00400 - - -
- - - 11343 S 0 60 1 e6002cbc 8400400 - - -
- - - 14289 S 0 60 1 22c4d670 c00400 - - -
- - - 14379 S 0 60 1 22c4d670 c00400 - - -
...
- - - 43187 S 0 60 1 701e6114 400400 - - -
- - - 43939 R 33 76 1 20039c88 c00000 - - -
- - - 50275 S 0 60 1 22c4d670 c00400 - - -
- - - 52477 S 0 60 1 e600ccbc 8400400 - - -
...
- - - 98911 S 0 60 1 7023d46c 400400 - - -
- - - 99345 R 33 76 0 - 400000 - - -
- - - 99877 S 0 60 1 22c4d670 c00400 - - -
- - - 100661 S 0 60 1 22c4d670 c00400 - - -
- - - 102599 S 0 60 1 22c4d670 c00400 - - -
...
「ST」の下に「R」という値を持つスレッドは「実行可能な」状態であるため、プロセッサー時間を累積することができます。 これらのスレッドで何が行われているかを見てみましょう。 ps からの出力は、スレッドごとの TID (カーネル・スレッド ID) を示しています。 これは、 dbxを使用して Java スレッド ID にマップできます。 dbx thread コマンドの出力は、以下の形式で表示されます。
thread state-k wchan state-u k-tid mode held scope function
$t1 wait 0xe60196bc blocked 104099 k no sys _pthread_ksleep
>$t2 run blocked 68851 k no sys _pthread_ksleep
$t3 wait 0x2015a458 running 29871 k no sys pthread_mutex_lock
...
$t50 wait running 86077 k no sys getLinkRegister
$t51 run running 43939 u no sys reverseHandle
$t52 wait running 56273 k no sys getLinkRegister
$t53 wait running 37797 k no sys getLinkRegister
$t60 wait running 4021 k no sys getLinkRegister
$t61 wait running 18791 k no sys getLinkRegister
$t62 wait running 99345 k no sys getLinkRegister
$t63 wait running 20995 k no sys getLinkRegister
ps からの TID 値と dbx thread コマンドからの k-tid 値を突き合わせることで、この場合の現在実行中のメソッドが reverseHandle および getLinkRegister であることが確認できます。
これで、 dbx を使用して、対応する dbx スレッド番号 ($tx) に dbx thread コマンドを使用することにより、これら 2 つのスレッドの C スレッド・スタックを生成することができます。 Java フレームを含むフル・スタック・トレースを取得するには、dbx スレッド番号をスレッド pthread_t 値にマップします。この値は、Javadump ファイルにリストされており、ダンプ・ビューアーを使用してスレッドごとに ExecEnv 構造体から取得できます。 これを行うには、 dbx コマンド thread
info [dbx thread number]を使用します。これにより、次の形式の出力が生成されます。
thread state-k wchan state-u k-tid mode held scope function
$t51 run running 43939 u no sys reverseHandle
general:
pthread addr = 0x220c2dc0 size = 0x18c
vp addr = 0x22109f94 size = 0x284
thread errno = 61
start pc = 0xf04b4e64
joinable = yes
pthread_t = 3233
scheduler:
kernel =
user = 1 (other)
event :
event = 0x0
cancel = enabled, deferred, not pending
stack storage:
base = 0x220c8018 size = 0x40000
limit = 0x22108018
sp = 0x22106930
この出力は、ps からの TID 値 (dbx の k-tid) が、pthread_t が 3233 の dbx スレッド番号 51 に対応していることを示しています。 Javadump ファイルの pthread_t を調べれば、以下のような完全なスタック・トレースを確認できます。
"Worker#31" (TID:0x36288b10, sys_thread_t:0x220c2db8) Native Thread State:
ThreadID: 00003233 Reuse: 1 USER SUSPENDED Native Stack Data : base: 22107f80
pointer 22106390 used(7152) free(250896)
----- Monitors held -----
java.io.OutputStreamWriter@3636a930
com.ibm.servlet.engine.webapp.BufferedWriter@3636be78
com.ibm.servlet.engine.webapp.WebAppRequestDispatcher@3636c270
com.ibm.servlet.engine.srt.SRTOutputStream@36941820
com.ibm.servlet.engine.oselistener.nativeEntry.NativeServerConnection@36d84490 JNI pinning lock
----- Native stack -----
_spin_lock_global_common pthread_mutex_lock - blocked on Heap Lock
sysMonitorEnterQuicker sysMonitorEnter unpin_object unpinObj
jni_ReleaseScalarArrayElements jni_ReleaseByteArrayElements
Java_com_ibm_servlet_engine_oselistener_nativeEntry_NativeServerConnection_nativeWrite
------ Java stack ------ () prio=5
com.ibm.servlet.engine.oselistener.nativeEntry.NativeServerConnection.write(Compiled Code)
com.ibm.servlet.engine.srp.SRPConnection.write(Compiled Code)
com.ibm.servlet.engine.srt.SRTOutputStream.write(Compiled Code)
java.io.OutputStreamWriter.flushBuffer(Compiled Code)
java.io.OutputStreamWriter.flush(Compiled Code)
java.io.PrintWriter.flush(Compiled Code)
com.ibm.servlet.engine.webapp.BufferedWriter.flushChars(Compiled Code)
com.ibm.servlet.engine.webapp.BufferedWriter.write(Compiled Code)
java.io.Writer.write(Compiled Code)
java.io.PrintWriter.write(Compiled Code)
java.io.PrintWriter.write(Compiled Code)
java.io.PrintWriter.print(Compiled Code)
java.io.PrintWriter.println(Compiled Code)
pagecompile._identifycustomer_xjsp.service(Compiled Code)
javax.servlet.http.HttpServlet.service(Compiled Code)
com.ibm.servlet.jsp.http.pagecompile.JSPState.service(Compiled Code)
com.ibm.servlet.jsp.http.pagecompile.PageCompileServlet.doService(Compiled Code)
com.ibm.servlet.jsp.http.pagecompile.PageCompileServlet.doGet(Compiled Code)
javax.servlet.http.HttpServlet.service(Compiled Code)
javax.servlet.http.HttpServlet.service(Compiled Code)
さらに、完全なスタック・トレースを使用することで、発生する可能性のある無限ループを特定できるはずです。 前の例は、spin_lock_global_commonの使用を示しています。これは、ロックでのビジー待機であるため、CPU時間が使用されます。