本コラムの対象:
「JavaVMが発行しているシステムコールを見てみよう!」という気になる方。
ネイティブな世界に足を踏み入れている方、または踏み入れようとしている方。
「コラム:ネイティブスレッドとJavaスレッドのマッピング」を読んで、「Windowsだとどうなの?」と気になる方。
0.はじめに
以前のコラム(ネイティブスレッドとJavaスレッドのマッピング)では、Solaris環境下で、ネイティブスレッドとJavaスレッドを対応づける方法を示しました。
今回はWindows環境下で、スレッドの対応付けを行う方法を示します。
このコラムの構成は以下の通りです。
| 今回の内容 |
|
◆ 1.サンプルプログラム このコラムで使用するサンプルプログラムを記述しています。 ◆ 2.スレッドダンプを取得する サンプルプログラム実行時のスレッドダンプを取得します。 ◆ 3.パフォーマンスモニタ Windowsのパフォーマンスモニタを使用して、CPUを消費しているスレッドのIDを突き止めます。 ◆ 4.スレッドダンプとの比較 突き止めたスレッドのIDとスレッドダンプから、CPUを消費しているJavaのスレッドを見つけます。 |
1.サンプルプログラム
今回のコラムでは以下のサンプルプログラムを使用します。
このプログラムでは、mainスレッドが無限ループしますので、CPU使用率が100%になります。
/**
* サンプルプログラム。
*/
public class PerfMonSampleMain
{
/**
* 強制的に終了させるまで、ループを繰り返す。
*/
public static void main(String[] args)
{
System.out.println("Program Start!");
while(true)
{
Thread.yield();
;
}
}
}
2.スレッドダンプを取得する
まず対象とするJavaアプリケーションのFull Thread Dumpを取得して下さい。
Windowsでは、コンソール画面でCTRL+BREAKを押すと取得できます。
Full thread dump Java HotSpot(TM) Client VM (1.5.0_04-b05 mixed mode, sharing):
"Low Memory Detector" daemon prio=5 tid=0x00a8e260 nid=0x3f4 runnable [0xFF000000..0xFF000000]
"CompilerThread0" daemon prio=10 tid=0x00a8ce38 nid=0x488 waiting on condition [0xFF000000..0x02c3f8cc]
"Signal Dispatcher" daemon prio=10 tid=0x00a9cd18 nid=0xdf0 waiting on condition [0xFF000000..0xFF000000]
"Finalizer" daemon prio=9 tid=0x0003fae8 nid=0x16c in Object.wait() [0x02bbf000..0x02bbfc68]
at java.lang.Object.wait(Native Method)
- waiting on <0x22be0840> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)
- locked <0x22be0840> (a java.lang.ref.ReferenceQueue$Lock)
at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132)
at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)
"Reference Handler" daemon prio=10 tid=0x00a67aa0 nid=0x810 in Object.wait() [0x02b7f000..0x02b7fce8]
at java.lang.Object.wait(Native Method)
- waiting on <0x22be0750> (a java.lang.ref.Reference$Lock)
at java.lang.Object.wait(Object.java:474)
at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
- locked <0x22be0750> (a java.lang.ref.Reference$Lock)
"main" prio=5 tid=0x000362f0 nid=0xb0c runnable [0x0007f000..0x0007fc3c]
at java.lang.Thread.yield(Native Method)
at PerfMonSampleMain.main(PerfMonSampleMain.java:13)
"VM Thread" prio=10 tid=0x00a87cd0 nid=0x9f4 runnable
"VM Periodic Task Thread" prio=10 tid=0x00a9cc58 nid=0xb8c waiting on condition
この中からCPUを100%消費しているスレッドを特定することになります。
Solarisではprstatやpstackを使用しましたが、Windowsではパフォーマンスモニタを使用します。
3.パフォーマンスモニタ
パフォーマンスモニタを使用して、CPUを消費しているスレッドを突き止めます。
以下の手順でカウンタの追加を行って下さい(下図)。
1) まず、パフォーマンス オブジェクトからThreadを選択します。
2) 続いて、カウンタから% Processor Timeを選択します。
3) 最後にインスタンスから、問題のJavaプロセスの全てのスレッドを選択し、追加ボタンを押します。
画面に表示されたグラフから、CPUを消費しているスレッドを特定します(下図)。
今回の場合はjava/0#2であることが分かります。
問題のスレッドがわかりましたので、このスレッドのIDを確認します。
以下の手順でカウンタを追加します(下図)。
1) パフォーマンス オブジェクトからThreadを選択します。
2) カウンタからID Threadを選択します。
3) インスタンスから、先の手順で見つけたスレッドを指定します。
グラフではわからないので、テーブルでカウンタを選択して下さい(下図)。
スレッドのIDは時間と共に変化はしないので、「最新」に出ている値がスレッドのIDになります。
(今回の場合、2828がjava/0#2のスレッドIDです。)
4.スレッドダンプとの比較
表示された値は10進数なので、これを16進数に変換します。
2828 => 0xb0c
この0xb0cが2で取得したスレッドダンプのnidと一致します。
スレッドダンプから0xb0cを探すと、以下のスレッドであることがわかります。
"main" prio=5 tid=0x000362f0 nid=0xb0c runnable [0x0007f000..0x0007fc3c]
at java.lang.Thread.yield(Native Method)
at PerfMonSampleMain.main(PerfMonSampleMain.java:13)
5.さいごに
いかがだったでしょうか。
サンプルプログラムのように、簡単なプログラムの場合は、 スレッドダンプを調べるだけでも、障害の原因となっているスレッドは見つけることができます。
しかし、アプリケーションサーバのように、スレッド数が数十~数百のオーダになる場合は、ここで示した方法を使用しないと、効率よく、障害原因のスレッドを突き止めることは困難です。







Copyright (C) 2008 Acroquest Technology Co., Ltd. All Rights Reserved.