ナビゲーションをスキップ

JRockit JDK ユーザーズ ガイド

  前 次 前/次ボタンと目次ボタンとの区切り線 目次  

スレッド ダンプでのスレッド アクティビティのモニタ

スレッド ダンプ (または「スレッド スタック トレース」) は、アプリケーションのアクティビティに関する情報を明らかにします。この情報は、問題を診断したり、アプリケーションと JVM のパフォーマンスを最適化したりするのに役立ちます。たとえば、スレッド ダンプには、アプリケーションのパフォーマンスに深刻な影響を与える「デッドロック」状態の発生が示されます。

Control-Break を呼び出して (通常は〔Ctrl〕+〔Break〕または〔Ctrl〕+〔¥〕を押すか、Linux 上で SIGQUIT を入力する)、スレッド ダンプを作成することができます。この節では、スレッド ダンプの扱い方について説明します。内容は以下のとおりです。

 


スレッド ダンプのロック情報

Control-Break または SIGQUIT を使用してスタック トレースを出力すると、BEA JRockit はアクティブなロックのステータス (モニタ) も表示します。スレッドが待機状態にある場合、BEA JRockit はスレッドごとに以下のような情報を出力します。

注意 : コンパイラの最適化が原因で、ロック情報のある行が必ずしも正確ではない場合があります。これは、2 つのことを意味します。

以上の点は通常は問題になりません。ロックの行の順序は正しい場所からそれほど大きく離れることはありません。また、ロックの行が失われることはなく、スレッドが取得したすべての行はスタック ダンプに必ず表示されます。

Java のオブジェクトにおける (通知の) 待機のセマンティクスは多少複雑です。最初にオブジェクトのロックを取得し、次にそのオブジェクトの wait() を呼び出す必要があります。wait メソッドでは、スレッドが通知を待機して実際にスリープ状態に入る前に、ロックが解放されます。通知を受け取ると、wait はロックを返す前に再び取得します。したがって、スレッドがロックを取得し、そのロック上で通知を待機している場合、ロックの取得時に記述されるスタック トレースの行には、「Holding lock」ではなく「Lock released while waiting」と表示されます。

すべてのロックは Classname@0xLockID[LockType] の形式で記述されます。次に例を示します。

java/lang/Object@0x105BDCC0[thin lock]

この例の説明は次のとおりです。

コード リスト 3-1 に、1 つのスレッドのスタック トレースの例を示します。

コード リスト 3-1 例 : 1 つのスレッドのスタック トレース

"Open T1" prio=5 id=0x680 tid=0x128 waiting
-- Waiting for notification on: java/lang/Object@0x1060FFC8[fat lock]
at jrockit/vm/Threads.waitForSignalWithTimeout(Native Method)@0x411E39C0
at jrockit/vm/Locks.wait(Locks.java:1563)@0x411E3BE5
at java/lang/Thread.sleep(Thread.java:244)@0x41211045
^-- Lock released while waiting: java/lang/Object@0x1060FFC8[fat lock]
at test/Deadlock.loopForever(Deadlock.java:67)@0x412304FC
at test/Deadlock$LockerThread.run(Deadlock.java:57)@0x4123042E
^-- Holding lock: java/lang/Object@0x105BDCC0[recursive]
^-- Holding lock: java/lang/Object@0x105BDCC0[thin lock]
at java/lang/Thread.startThreadFromVM(Thread.java:1690)@0x411E5F73
--- End of stack trace

 


デッドロックの検出

通常のスタック ダンプの後、BEA JRockit はデッドロックの検出を行います。まず、Java アプリケーションで「ロック チェーン」を検索します。ロック チェーンの循環が見つかると、アプリケーションはデッドロックに入っていると見なされます。

「ロック チェーン」とは

多少複雑に見えるかもしれませんが、ロック チェーンはかなり簡単なものです。ロック チェーンとは、一連のスレッドのそれぞれが、チェーン内の次のスレッドにより保持されているロックを待機している状態、と言えるでしょう。開いたロック チェーンとは、最後のスレッドがロックを取得しようとはせず、代わりに実際の作業をしているか何らかの外部イベントを待機している状態です。循環チェーンとはデッドロックであり、それが解決されることは決してありません。閉じたチェーンは、別のロック チェーンに依存しています。依存している別のロック チェーンがデッドロックであればそれもデッドロックとなり、別のロック チェーンが開いていればそれも開きます。閉じたチェーンとは、複数のスレッドが同じロックを取得しようとしている状態と言えるでしょう。

ロック チェーンの詳細な解説

  1. スレッド Ta が取得しようとしているロックをスレッド Tb が保持している場合、この 2 つのスレッドはロック チェーン Ta->Tb を形成します。
  2. Ta->Tb がロック チェーンであり、スレッド Tb が取得しようとしているロック Lc をスレッド Tc が保持している場合、Ta->Tb->Tc もまたロック チェーンを形成します。
  3. Ta->...->Tn がロック チェーンであり、スレッド Ta が保持しているロック La が存在せず、スレッド Tx がロック La を取得しようとしている場合、そのロック チェーンは Ta始点となります。
  4. Ta->...->Tn がスレッド Ta を起点とするロック チェーンであり、存在しないロック Lx をスレッド Tn が取得しようとしている場合、Ta->...->Tn開いたロック チェーンであり、Tn終点となります。
  5. Ta->...->Tn がスレッド Ta を始点とするロック チェーンであり、スレッド To が保持しているロック Lo をスレッド Tn が取得しようとしていて、しかもスレッド To が別の完全なロック チェーンに含まれている場合、Ta->...->Tn閉じたロック チェーンであり、Tn終点 となります。
  6. Ta->...->Tn がロック チェーンであり、Ta が保持しているロック La をスレッド Tn が取得しようとしている場合、Ta->...->Tn循環 (デッドロック) ロック チェーンとなります。
  7. 開いたロック チェーン、閉じたロック チェーン、または循環ロック チェーンは、完全なロック チェーンです。

上記の定義から、ロックを取得しようとしているすべてのスレッドが 1 つの完全なロック チェーンに含まれていることが理解できます。

ロック チェーンのダンプ

BEA JRockit はすべての完全なロック チェーンを発見し、それらを開いたロック チェーン、閉じたロック チェーン、循環ロック チェーンにグループ分けします。開いたロック チェーンと閉じたロック チェーンはどれも、始点から終点まですべての要素が出力されます。循環ロック チェーンについては、始点も終点も存在しないため、任意の要素を選択してそれを始点として扱います。

閉じたチェーンと別のチェーンの間の区分は任意です。2 つの異なるスレッドが同じロックを取得しようとしてブロックされると、閉じたチェーンが発生します。たとえば、Thread A が保持している Lock A を、Thread BThread C の両者が待機している場合などです。BEA JRockit はこの状況を次のいずれかに解釈します。

デッドロックしたロック チェーンは解決できないため、アプリケーションは無限に待機してスタックする可能性があります。長くて開いたロック チェーンがある場合、アプリケーションはロックを待機して時間を無駄に消費する可能性があります。

 

ページの先頭 前 次