コラム: ネイティブスレッドとJavaスレッドのマッピング (Windows編)



ネイティブスレッドとJavaスレッドのマッピング (Windows編)

本コラムの対象:
「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プロセスの全てのスレッドを選択し、追加ボタンを押します。

Processor Time

画面に表示されたグラフから、CPUを消費しているスレッドを特定します(下図)。

CPU

今回の場合はjava/0#2であることが分かります。

問題のスレッドがわかりましたので、このスレッドのIDを確認します。
以下の手順でカウンタを追加します(下図)。

1) パフォーマンス オブジェクトからThreadを選択します。
2) カウンタからID Threadを選択します。
3) インスタンスから、先の手順で見つけたスレッドを指定します。

Thread ID


グラフではわからないので、テーブルでカウンタを選択して下さい(下図)。
スレッドのIDは時間と共に変化はしないので、「最新」に出ている値がスレッドの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.さいごに

いかがだったでしょうか。
サンプルプログラムのように、簡単なプログラムの場合は、 スレッドダンプを調べるだけでも、障害の原因となっているスレッドは見つけることができます。

しかし、アプリケーションサーバのように、スレッド数が数十~数百のオーダになる場合は、ここで示した方法を使用しないと、効率よく、障害原因のスレッドを突き止めることは困難です。

Page Top

注意:本文書の内容に誤りがあり、またこの文書によって不利益を被っても、
Acroquest Technology 株式会社は一切関知いたしません。

  • 現象別Index
  • 原因別Index

Find Bugsバグ詳細

Find Bugs Bug Descriptions日本語版

RSSで更新情報を取得する

RSSとは、ホームページの更新情報を配信する為のフォーマットです。
RSSを利用すると、登録したページの情報が更新された場合に、更新情報を自動的に受け取る事ができます。

詳細

弊社小森が執筆致しました

Javaでオブジェクト指向開発

Javaプログラミング言語習得において、新人プログラマーの最初の障害は「オブジェクト指向の壁」です。
本書は、Javaのソフトウェア開発を中心に事業を発展させてきたAcroquest社の新人教育セミナーを加筆・書籍化したもので、大卒の新人に対して、ゼロからJava言語を教えてきた実績をフィードバックしています。

メールマガジン配信中

Javaトラブルシューティングのメルマガをはじめました!是非ご購読ください

詳細