JRockit Management Console ユーザーズ ガイド (JRockit 1.4.2 R26)

     前  次    目次     
コンテンツの開始位置

スタック ダンプによるスレッド アクティビティの追跡

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

通常、スタック ダンプは特定のエラーが送出されたときに発生します。control break を呼び出して (通常は、〔Ctrl〕+〔Break〕または〔Ctrl〕+〔¥〕を押すか、Linux 上で SIGQUIT を入力する)、スタック ダンプを作成することもできます。この節では、スタック ダンプの扱い方について説明します。内容は以下のとおりです。

 


スタック ダンプの情報のモニタ

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

スレッドがロックを取得しようとした (同期ロックに入ろうとした) ものの、別のスレッドがすでにロックを保持している場合は、スタック トレースの先頭に「Blocked trying to get lock」と表示されます。

(Object.wait() を呼び出して) スレッドがロック上で通知を待機している場合は、スタック トレースの先頭に「Waiting for notification」と表示されます。

スレッドがロックを取得している場合もスタック トレースに表示されます。関数呼び出しを表すスタック トレースの行の後に、その関数でスレッドが取得したロックのリストが「^-- Holding lock」のように記述されます (^-- は、ロックがその上の行の関数で取得されたものであることを示しています)。

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

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

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

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

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

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

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

コード リスト B-7 例 : 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 アプリケーションで「ロック チェーン」を検索することにより行われます。 ロック チェーンの循環が見つかると、アプリケーションはデッドロックに入っていると見なされます。

「ロック チェーン」とは

多少複雑に見えるかもしれませんが、ロック チェーンは簡単なものであり、次のように定義できます。

ロック チェーンのタイプ

BEA JRockit はスレッドを分析して完全なロック チェーンを形成します。ロック チェーンには開いたロック チェーン、デッドロック チェーン、閉じたロック チェーンの 3 種類あります。

開いたチェーン

ロック チェーンとは」で述べたように、開いたロック チェーンは直線的な依存関係を表します。スレッド A が B を待機し、B が C を待機している場合などです。

デッドロック チェーン

デッドロック (循環) チェーンは開いたロック チェーンに似ていますが、最初の要素が最後の要素を待機している点が異なります。最も単純な例は、A が B を待機し、B が A を待機している場合です。デッドロック チェーンには先頭がありません。BEA JRockit は任意のスレッドを選択して、チェーンの最初の要素として表示します。

閉じたチェーン

閉じたチェーンは開いたチェーンに似ていますが、チェーンの最初の要素が別のチェーンのロックを待機しています。この別のチェーンは、開いたチェーン、デッドロック チェーン、閉じたチェーンのいずれの場合もあります。別のチェーンがデッドロックになると、閉じたチェーンもデッドロックになります。閉じたチェーンと別のチェーンの間の区分は任意です。

2 つの異なるスレッドが同じロックを取得しようとしてブロックされると、閉じたチェーンが発生します。たとえば、スレッド A がロック A を保持していてるときに、スレッド B がロック A を待機しており、スレッド C もロック A を待機している場合などです。BEA JRockit はこの状況を次のいずれかに解釈します。

おそらく、ユーザの関心があるのはデッドロック チェーンがあるかどうかでしょう。デッドロック チェーンを解決しないと、アプリケーションは無限に待機してスタックする可能性があります。また、長くて開いたロック チェーンがある場合、アプリケーションはロックを待機して時間を無駄に消費する可能性があります。


  ページの先頭       前  次