AIX® ビジー・ハング

スレッド間でデッドロックが発生していない場合は、スレッドが正常に実行されない別の理由を考慮してください。

通常、この状態は以下のいずれかの理由により発生します。
  1. 実行すべき処理が「通知される」のを、スレッドが「待機している」状態である。
  2. スレッドが明示的にスリープ状態を繰り返す。
  3. 入出力が実行されるようになるまで、スレッドが入出力呼び出しを待機している。
最初の 2 つの理由は、Java™ コード (アプリケーションのコード、または SDK に含まれている標準クラス・ファイルのコード) に障害があることを意味します。

スレッドが (例えば、ソケットで) 入出力を待機しているという 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 値 (dbxk-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時間が使用されます。