印刷ビューの終了

HotSpot VM のトラブルシューティングガイド

印刷ビュー

ドキュメント情報

はじめに

1. 診断ツールおよびオプション

2. ツールの詳細な説明

2.1 HPROF - ヒーププロファイラ

2.1.1 ヒープ割り当てプロファイル (heap=sites)

2.1.2 ヒープダンプ (heap=dump)

2.1.3 CPU 使用率サンプリングプロファイル (cpu=samples)

2.1.4 CPU 使用時間プロファイル (cpu=times)

2.2 Java VisualVM

2.3 JConsole ユーティリティー

2.4 jdb ユーティリティー

2.4.1 プロセスへの接続

2.4.2 同一マシン上のコアファイルへの接続

2.4.3 別のマシン上のコアファイルまたはハングアッププロセスへの接続

2.5 jhat ユーティリティー

2.5.1 標準クエリー

2.5.1.1 「すべてのクラス」クエリー

2.5.1.2 「クラス」クエリー

2.5.1.3 「オブジェクト」クエリー

2.5.1.4 「インスタンス」クエリー

2.5.1.5 「ルート」クエリー

2.5.1.6 「到達可能なオブジェクト」クエリー

2.5.1.7 「すべてのクラスのインスタンス数」クエリー

2.5.1.8 「すべてのルート」クエリー

2.5.1.9 「新規インスタンス」クエリー

2.5.1.10 ヒストグラムクエリー

2.5.2 カスタムクエリー

2.5.3 ヒープ分析のヒント

2.5.3.1 何がオブジェクトをライブに保っているのか。

2.5.3.2 このオブジェクトはどこで割り当てられたのか。

2.6 jinfo ユーティリティー

2.7 jmap ユーティリティー

2.7.1 ヒープの構成と使用量

2.7.2 実行中のプロセスのヒープヒストグラム

2.7.3 コアファイルのヒープヒストグラム

2.7.4 Permanent 世代に関する情報の取得

2.8 jps ユーティリティー

2.9 jrunscript ユーティリティー

2.10 jsadebugd デーモン

2.11 jstack ユーティリティー

2.11.1 スタックダンプの強制

2.11.2 コアダンプからのスタックトレースの出力

2.11.3 混合スタックの出力

2.12 jstat ユーティリティー

2.12.1 -gcutil オプションの例

2.12.2 -gcnew オプションの例

2.12.3 -gcoldcapacity オプションの例

2.13 jstatd デーモン

2.14 visualgc ツール

2.15 Ctrl-Break ハンドラ

2.15.1 スレッドダンプ

2.15.2 デッドロックの検出

2.15.3 ヒープサマリー

2.16 オペレーティングシステム固有のツール

2.16.1 Solaris オペレーティングシステム

2.16.2 Linux オペレーティングシステム

2.16.3 Windows オペレーティングシステム

2.16.4 Solaris 10 OS で導入されたツール

2.16.4.1 pmap ツールの改善

2.16.4.2 pstack ツールの改善

2.16.4.3 DTrace ツールの使用

Java HotSpot VM のプローブプロバイダ

DTrace の使用例

2.17 診断ツールの開発

2.17.1 java.lang.management パッケージ

2.17.2 java.lang.instrument パッケージ

2.17.3 java.lang.Thread クラス

2.17.4 Java Virtual Machine Tools Interface

2.17.5 Java Platform Debugger Architecture

3. メモリーリークのトラブルシューティング

4. システムクラッシュのトラブルシューティング

5. ハングアップまたはループしているプロセスのトラブルシューティング

6. シグナル処理と例外処理の統合

7. バグレポートの提出

A. 環境変数とシステムプロパティー

B. コマンド行オプション

C. 致命的エラーログ

D. このリリースのツールのサマリー

第 2 章

ツールの詳細な説明

この章では、JDK 7 で使用可能なトラブルシューティングツールについて詳しく説明します。さらにこの章では、これらのトラブルシューティングツールと組み合わせて使用可能なオペレーティングシステム固有のツールの一覧を示します。最後にこの章では、JDK 7 で提供される API を使って新しいツールをどのようにして開発できるかを説明します。

この章には、次のセクションがあります。

2.1 HPROF - ヒーププロファイラ

ヒーププロファイラ (HPROF) ツールは、JDK リリースに付属する単純なプロファイラエージェントです。これは、Java Virtual Machine Tools Interface (JVM TI) を使って Java VM とインタフェースする、動的にリンクされたライブラリです。このツールは、プロファイル情報をファイルまたはソケットに ASCII 形式またはバイナリ形式で書き込みます。この情報はさらに、プロファイラフロントエンドツールを使って処理できます。

HPROF ツールでは、CPU 使用率、ヒープ割り当ての統計、およびモニター競合プロファイルを表示できます。さらに、完全なヒープダンプや、Java 仮想マシン内のすべてのモニターとスレッドの状態を報告できます。問題の診断に関して、HPROF はパフォーマンス、ロック競合、メモリーリークなどの問題を分析する際に役立ちます。

JDK リリースには HPROF ライブラリだけでなく、HPROF のソースも JVM TI のデモコードとして含まれています。このコードは $JAVA_HOME/demo/jvmti/hprof ディレクトリにあります。

HPROF ツールは次のように呼び出されます。

$ java -agentlib:hprof ToBeProfiledClass

HPROF は要求されたプロファイルの種類に応じて、関連するイベントを送信するように仮想マシンに指示します。その後、ツールはイベントデータをプロファイル情報に処理します。たとえば、次のコマンドはヒープ割り当てプロファイルを取得します。

$ java -agentlib:hprof=heap=sites ToBeProfiledClass

次に示すように、HPROF エージェントに help オプションを指定すると、オプションの完全な一覧が出力されます。

$ java -agentlib:hprof=help
     HPROF: Heap and CPU Profiling Agent (JVMTI Demonstration Code)
hprof usage: java -agentlib:hprof=[help]|[<option>=<value>, ...]
Option Name and Value  Description                    Default
---------------------  -----------                    -------
heap=dump|sites|all    heap profiling                 all
cpu=samples|times|old  CPU usage                      off
monitor=y|n            monitor contention             n
format=a|b             text(txt) or binary output     a
file=<file>            write data to file             java.hprof[{.txt}]
net=<host>:<port>      send data over a socket        off
depth=<size>           stack trace depth              4
interval=<ms>          sample interval in ms          10
cutoff=<value>         output cutoff point            0.0001
lineno=y|n             line number in traces?         y
thread=y|n             thread in traces?              n
doe=y|n                dump on exit?                  y
msa=y|n                Solaris micro state accounting n
force=y|n              force output to <file>         y
verbose=y|n            print messages about dumps     y
Obsolete Options
----------------
gc_okay=y|n
<>
Examples
--------
  - Get sample cpu information every 20 millisec, with a stack depth of 3:
      java -agentlib:hprof=cpu=samples,interval=20,depth=3 classname
  - Get heap usage information based on the allocation sites:
      java -agentlib:hprof=heap=sites classname
Notes
-----
  - The option format=b cannot be used with monitor=y.
  - The option format=b cannot be used with cpu=old|times.
  - Use of the -Xrunhprof interface can still be used, e.g.
       java -Xrunhprof:[help]|[<option>=<value>, ...]
    will behave exactly the same as:
       java -agentlib:hprof=[help]|[<option>=<value>, ...]
Warnings
--------
  - This is demonstration code for the JVMTI interface and use of BCI,
    it is not an official product or formal part of the JDK.
  - The -Xrunhprof interface will be removed in a future release.
  - The option format=b is considered experimental, this format may change
    in a future release.

ヒーププロファイル情報 (サイトとダンプ) はデフォルトで、現在の作業ディレクトリ内の java.hprof.txt に (ASCII で) 書き出されます。

出力は通常、VM 終了時に生成されますが、それを無効にするには、「終了時にダンプ」オプションを「n」に設定します (doe=n)。さらに、(プラットフォームに応じて) Ctrl-\ または Ctrl-Break を押すと、プロファイルが生成されます。Solaris OS および Linux の場合、QUIT シグナルが受信された (kill -QUIT pid) 場合にもプロファイルが生成されます。Ctrl-\ または Ctrl-Break を複数回押すと、1 つのファイルに複数のプロファイルが生成されます。

ほとんどの場合、出力にはトレース、スレッド、およびオブジェクトの ID が含まれています。それぞれのタイプの ID は通常、ほかの ID とは異なる番号から始まります。たとえば、トレースは 300000 から始まります。

2.1.1 ヒープ割り当てプロファイル (heap=sites)

次の出力は、一連の入力ファイルに対して Java コンパイラ (javac) を実行することで生成されたヒープ割り当てプロファイルです。ここでは、プロファイラ出力の一部のみを示します。

$ javac -J-agentlib:hprof=heap=sites Hello.java
SITES BEGIN (ordered by live bytes) Wed Oct 4 13:13:42 2006
          percent          live          alloc'ed  stack class
 rank   self  accum     bytes objs     bytes  objs trace name
    1 44.13% 44.13%   1117360 13967  1117360 13967 301926 java.util.zip.ZipEntry
    2  8.83% 52.95%    223472 13967   223472 13967 301927 com.sun.tools.javac.util.List
    3  5.18% 58.13%    131088    1    131088     1 300996 byte[]
    4  5.18% 63.31%    131088    1    131088     1 300995 com.sun.tools.javac.util.Name[]

ヒーププロファイル内の重要な情報は、プログラムのさまざまな部分で行われる割り当ての量です。上の SITES レコードは、合計容量の 44.13% が java.util.zip.ZipEntry オブジェクトに割り当てられたことを示しています。

割り当てサイトをソースコードに関連付けるには、ヒープ割り当ての原因となった動的スタックトレースを記録するのが早道です。次の出力は、プロファイラ出力の別の部分を示しています。この出力は、上記の出力で 4 つの割り当てサイトによって参照されていたスタックトレースを示しています。

TRACE 301926:
        java.util.zip.ZipEntry.<init>(ZipEntry.java:101)
        java.util.zip.ZipFile+3.nextElement(ZipFile.java:417)
        com.sun.tools.javac.jvm.ClassReader.openArchive(ClassReader.java:1374)
        com.sun.tools.javac.jvm.ClassReader.list(ClassReader.java:1631)
TRACE 301927:
        com.sun.tools.javac.util.List.<init>(List.java:42)
        com.sun.tools.javac.util.List.<init>(List.java:50)
        com.sun.tools.javac.util.ListBuffer.append(ListBuffer.java:94)
        com.sun.tools.javac.jvm.ClassReader.openArchive(ClassReader.java:1374)
TRACE 300996:
        com.sun.tools.javac.util.Name$Table.<init>(Name.java:379)
        com.sun.tools.javac.util.Name$Table.<init>(Name.java:481)
        com.sun.tools.javac.util.Name$Table.make(Name.java:332)
        com.sun.tools.javac.util.Name$Table.instance(Name.java:349)
TRACE 300995:
        com.sun.tools.javac.util.Name$Table.<init>(Name.java:378)
        com.sun.tools.javac.util.Name$Table.<init>(Name.java:481)
        com.sun.tools.javac.util.Name$Table.make(Name.java:332)
        com.sun.tools.javac.util.Name$Table.instance(Name.java:349)

スタックトレースの各フレームには、クラス名、メソッド名、ソースファイル名、および行番号が含まれています。ユーザーは、HPROF エージェントによって収集されるフレームの最大数を設定できます。デフォルトの上限は 4 です。スタックトレースには、ヒープ割り当てを行なったメソッドだけでなく、最終的にメモリー割り当てが発生する呼び出しを行なったメソッドも表示されます。

2.1.2 ヒープダンプ (heap=dump)

ヒープダンプは heap=dump オプションを使って取得されます。ヒープダンプの形式は、format オプションの設定に応じて ASCII、バイナリのいずれかです。jhat (「2.5 jhat ユーティリティー」を参照) などのツールではバイナリ形式が使用されるので、format=b オプションが必要となります。バイナリ形式が指定された場合、プリミティブ型のインスタンスフィールドとプリミティブ配列の内容がダンプに含まれます。

次のコマンドでは、javac コンパイラを実行することでダンプが生成されます。

$ javac -J-agentlib:hprof=heap=dump Hello.java

出力は大きなファイルになります。これは、ガベージコレクタによって決定されたルートセットと、そのルートセットから到達可能なヒープ内の各 Java オブジェクトごとのエントリから構成されます。次は、サンプルヒープダンプから選択されたいくつかのレコードです。

HEAP DUMP BEGIN (39793 objects, 2628264 bytes) Wed Oct 4 13:54:03 2006
ROOT 50000114 (kind=<thread>, id=200002, trace=300000)
ROOT 50000006 (kind=<JNI global ref>, id=8, trace=300000)
ROOT 50008c6f (kind=<Java stack>, thread=200000, frame=5)
:
CLS 50000006 (name=java.lang.annotation.Annotation, trace=300000)
    loader        90000001
OBJ 50000114 (sz=96, trace=300001, class=java.lang.Thread@50000106)
    name        50000116
    group        50008c6c
    contextClassLoader    50008c53
    inheritedAccessControlContext    50008c79
    blockerLock    50000115
OBJ 50008c6c (sz=48, trace=300000, class=java.lang.ThreadGroup@50000068)
    name        50008c7d
    threads    50008c7c
    groups        50008c7b
ARR 50008c6f (sz=16, trace=300000, nelems=1, 
     elem type=java.lang.String[]@5000008e)
    [0]        500007a5
CLS 5000008e (name=java.lang.String[], trace=300000)
    super        50000012
    loader        90000001
:
HEAP DUMP END

各レコードは、ルート、オブジェクトインスタンス、クラス、または配列を表す ROOTOBJCLS、または ARR です。16 進数は、HPROF によって割り当てられた識別子です。これらの数値は、あるオブジェクトから別のオブジェクトへの参照を示すために使用されます。たとえば上のサンプルでは、java.lang.Thread インスタンス 50000114 が、スレッドグループ (50008c6c) やその他のオブジェクトへの参照を持っています。

一般に出力のサイズは非常に大きいので、ツールを使ってヒープダンプの出力を視覚化または処理する必要があります。そのようなツールの 1 つが jhat です。「2.5 jhat ユーティリティー」を参照してください。

2.1.3 CPU 使用率サンプリングプロファイル (cpu=samples)

HPROF ツールは、スレッドのサンプリングによって CPU 使用率の情報を収集できます。次は、javac コンパイラの実行から収集された出力の一部です。

$ javac -J-agentlib:hprof=cpu=samples Hello.java
CPU SAMPLES BEGIN (total = 462) Wed Oct 4 13:33:07 2006
rank   self  accum   count trace method
   1 49.57% 49.57%     229 300187 java.util.zip.ZipFile.getNextEntry
   2  6.93% 56.49%      32 300190 java.util.zip.ZipEntry.initFields
   3  4.76% 61.26%      22 300122 java.lang.ClassLoader.defineClass2
   4  2.81% 64.07%      13 300188 java.util.zip.ZipFile.freeEntry
   5  1.95% 66.02%       9 300129 java.util.Vector.addElement
   6  1.73% 67.75%       8 300124 java.util.zip.ZipFile.getEntry
   7  1.52% 69.26%       7 300125 java.lang.ClassLoader.findBootstrapClass
   8  0.87% 70.13%       4 300172 com.sun.tools.javac.main.JavaCompiler.<init>
   9  0.65% 70.78%       3 300030 java.util.zip.ZipFile.open
  10  0.65% 71.43%       3 300175 com.sun.tools.javac.main.JavaCompiler.<init>

...
CPU SAMPLES END

HPROF エージェントは、実行中のすべてのスレッドのスタックを定期的にサンプリングし、もっとも頻繁にアクティブになるスタックトレースを記録します。上の count フィールドは、特定のスタックトレースがアクティブであることが見つかった回数を示しています。これらのスタックトレースは、アプリケーション内の CPU 使用率のホットスポットに相当します。

2.1.4 CPU 使用時間プロファイル (cpu=times)

HPROF ツールは、CPU 使用率の情報を収集するために、あらゆるメソッドの入口と出口にコードを挿入し、それによって正確なメソッド呼び出し回数と各メソッド内で費やされた時間を追跡します。このプロセスではバイトコードインジェクション (BCI) が使用されるため、実行速度は cpu=samples オプションよりもかなり低下します。次は、javac コンパイラの実行から収集された出力の一部です。

$ javac -J-agentlib:hprof=cpu=times Hello.java
CPU TIME (ms) BEGIN (total = 2082665289) Wed oct 4 13:43:42 2006
rank   self  accum   count trace method
   1  3.70%  3.70%       1 311243 com.sun.tools.javac.Main.compile
   2  3.64%  7.34%       1 311242 com.sun.tools.javac.main.Main.compile
   3  3.64% 10.97%       1 311241 com.sun.tools.javac.main.Main.compile
   4  3.11% 14.08%       1 311173 com.sun.tools.javac.main.JavaCompiler.compile
   5  2.54% 16.62%       8 306183 com.sun.tools.javac.jvm.ClassReader.listAll
   6  2.53% 19.15%      36 306182 com.sun.tools.javac.jvm.ClassReader.list
   7  2.03% 21.18%       1 307195 com.sun.tools.javac.comp.Enter.main
   8  2.03% 23.21%       1 307194 com.sun.tools.javac.comp.Enter.complete
   9  1.68% 24.90%       1 306392 com.sun.tools.javac.comp.Enter.classEnter
  10  1.68% 26.58%       1 306388 com.sun.tools.javac.comp.Enter.classEnter
...
CPU TIME (ms) END

この出力で、count はこのメソッドに入った本当の回数を表し、パーセンテージはこれらのメソッドで費やされたスレッド CPU 時間の尺度を表します。

2.2 Java VisualVM

Java VisualVM は、JDK ダウンロード (JDK release 7 update 7 以降) に含まれるツールの 1 つです。このツールは、Java アプリケーションの開発者が、アプリケーションのトラブルシューティングを行なったり、アプリケーションのパフォーマンスを監視および改善したりするのに役立ちます。Java VisualVM を使用すると、ヒープダンプの生成および解析、メモリーリークの特定、ガベージコレクションの実行およびモニター、およびメモリーと CPU の簡易プロファイリングの実行が可能になります。またこのツールは、チューニング、ヒープサイズ決定、オフライン分析、およびポストモーテム診断にも役立ちます。

さらに、Java VisualVM の機能を拡張する既存のプラグインを使用することもできます。たとえば、JConsole ツールのほとんどの機能が、MBeans タブおよび JConsole プラグインラッパータブを介して使用できます。標準 Java VisualVM プラグインのカタログから選択するには、Java VisualVM のメインウィンドウの「ツール」メニューから「プラグイン」を選択します。

Java VisualVM の包括的なドキュメントについては、http://download.oracle.com/javase/7/docs/technotes/guides/visualvm/index.html を参照してください

Java VisualVM では次のトラブルシューティングアクティビティーを実行できます。

Java VisualVM を起動するとメインのアプリケーションウィンドウが開き、ローカルマシン上で実行されている Java アプリケーションの一覧、接続されたすべてのリモートマシン上で実行されている Java アプリケーションの一覧、取得して保存されたすべての VM コアダンプの一覧 (Solaris OS および Linux の場合)、取得して保存されたすべてのアプリケーションスナップショットの一覧が表示されます。

Java VisualVM は、JDK 7 上で実行されている Java アプリケーションや、バージョン 5.0 上で正しいシステムプロパティーとともに起動された Java アプリケーションの JMX エージェントを自動的に検出して接続します。リモートマシン上のエージェントをツールが検出して接続するためには、リモートマシン上で jstatd デーモンが実行されている必要があります (「2.13 jstatd デーモン」を参照)。ターゲットアプリケーション内で実行されている JMX エージェントを Java VisualVM が自動的に発見して接続できない場合のために、ツールにはそれらの接続を明示的に作成する方法が用意されています。

2.3 JConsole ユーティリティー

JDK ダウンロードに含まれるもう 1 つの便利なツールは、JConsole モニタリングツールです。このツールは Java Management Extensions (JMX) に準拠しています。このツールは、Java 仮想マシンの組み込み JMX インストゥルメンテーションを使って、実行中のアプリケーションのパフォーマンスやリソース消費に関する情報を提供します。このツールは、JDK ダウンロードに含まれてはいますが、Java 実行環境で配備されたアプリケーションのモニターや管理にも使用できます。

JConsole ツールは、スレッド使用量やメモリー消費量などの有用な情報、およびクラスロード、実行時コンパイル、オペレーティングシステムに関する詳細情報を表示する目的で、任意の Java アプリケーションに接続できます。

この出力は、メモリーリーク、過剰なクラスロードや実行中のスレッドなどの問題の高レベルの診断に役立ちます。これは、チューニングやヒープサイズ決定にも役立つ可能性があります。

JConsole を使えば、モニタリングだけでなく、実行中のシステム内のいくつかのパラメータを動的に変更することもできます。たとえば、-verbose:gc オプションの設定を変更できるので、実行中のアプリケーションに対するガベージコレクションのトレース出力を動的に有効または無効にできます。

次のリストは、JConsole ツールを使ってモニターできるデータの概要を示しています。各見出しはツール内のタブペインに対応しています。

JConsole は、ローカルアプリケーションとリモートアプリケーションの両方をモニターできます。接続先 JMX エージェントを指定する引数付きでツールを起動した場合、ツールは指定されたアプリケーションのモニタリングを自動的に開始します。

ローカルアプリケーションをモニターするには、コマンド jconsole pid (pid はアプリケーションのプロセス ID) を実行します。

リモートアプリケーションをモニターするには、コマンド jconsole hostname:portnumber (hostname はアプリケーションを実行しているホストの名前、portnumber は JMX エージェントの有効化時に指定したポート番号) を実行します。

jconsole コマンドを引数なしで実行した場合、ツールはまず、モニター対象のローカルまたはリモートプロセスを指定するための「新規接続」ウィンドウを表示します。「接続」メニューを使えば別のホストにいつでも接続できます。

JDK 1.5 リリースでは、-Dcom.sun.management.jmxremote オプションでモニター対象のアプリケーションを起動する必要があります。JDK 7 リリースでは、モニター対象アプリケーションを起動する際にオプションは不要です。

モニタリングツールの出力例として、次の画面はヒープメモリー使用量のグラフを示しています。

JConsole からのサンプル出力
Java モニタリングおよび管理コンソール (JConsole)、「メモリー」タブ

JConsole ツールの完全なチュートリアルは、このドキュメントの対象外です。ただし、次の各ドキュメントでは、モニタリングおよび管理機能や JConsole の使用方法について、より詳しく説明されています。

2.4 jdb ユーティリティー

jdb ユーティリティーは、コマンド行デバッガの例として JDK リリースに含まれています。jdb ユーティリティーは、Java Debug Interface (JDI) を使ってターゲット VM を起動または接続します。$JAVA_HOME/demo/jpda/examples.jar には jdb のソースコードが含まれています。

Java Debug Interface (JDI) は、(通常はリモートの) 仮想マシンの実行状態にアクセスする必要があるデバッガや同様のシステムに役立つ情報を提供する、高レベルの Java API です。JDI は Java Platform Debugger Architecture (JPDA) のコンポーネントです。「2.17.5 Java Platform Debugger Architecture」を参照してください。

JDI のコネクタは、デバッガがターゲット仮想マシンに接続するための手段です。JDK リリースには従来、ターゲット VM とのデバッグセッションを開始して確立するコネクタと、(TCP/IP または共有メモリートランスポートを使用した) リモートデバッグに使用されるコネクタが付属していました。

JDK リリースにはさらに、Java 言語デバッガからクラッシュダンプやハングアッププロセスに接続することを許可する、Serviceability Agent (SA) コネクタもいくつか付属しています。これは、クラッシュまたはハングアップの際にアプリケーションが何をしていたのかを確認するのに役立つ可能性があります。

これらのコネクタは SACoreAttachingConnector、SADebugServerAttachingConnector、および SAPIDAttachingConnector です。

これらのコネクタは一般に、エンタープライズデバッガ (NetBeans IDE や商用 IDE など) で使用されます。次のサブセクションでは、jdb コマンド行デバッガでこれらのコネクタを使用する方法を示します。

コネクタの詳細については、http://download.oracle.com/javase/7/docs/technotes/guides/jpda/conninv.html#Connectors を参照してください。

コマンド jdb -listconnectors は、使用可能なコネクタの一覧を出力します。コマンド jdb -help は、コマンドの使用方法を出力します。

jdb ユーティリティーの詳細については、マニュアルページを参照してください。

2.4.1 プロセスへの接続

この例では、SA PID 接続コネクタを使ってプロセスに接続します。ターゲットプロセスは、特別なオプションを付けて起動されません (つまり、-agentlib:jdwp オプションは不要です)。このコネクタがプロセスに接続する際は、読み取り専用モードで行われます。デバッガは、スレッドや実行中のアプリケーションを検査することはできますが、何かを変更することはできません。デバッガが接続されている間、プロセスは凍結されます。

次の例のコマンドは、sun.jvm.hotspot.jdi.SAPIDAttachingConnector という名前のコネクタを使用するように jdb に指示しています。これはクラス名ではなくコネクタ名です。コネクタは pid という名前の引数を 1 つ取ります (値はターゲットプロセスのプロセス ID、この例では 9302 です)。

$ jdb -connect sun.jvm.hotspot.jdi.SAPIDAttachingConnector:pid=9302

Initializing jdb ...
> threads
Group system:
  (java.lang.ref.Reference$ReferenceHandler)0xa Reference Handler unknown
  (java.lang.ref.Finalizer$FinalizerThread)0x9  Finalizer         unknown
  (java.lang.Thread)0x8                         Signal Dispatcher running
  (java.lang.Thread)0x7                         Java2D Disposer   unknown
  (java.lang.Thread)0x2                         TimerQueue        unknown
Group main:
  (java.lang.Thread)0x6                         AWT-XAWT          running
  (java.lang.Thread)0x5                         AWT-Shutdown      unknown
  (java.awt.EventDispatchThread)0x4             AWT-EventQueue-0  unknown
  (java.lang.Thread)0x3                         DestroyJavaVM     running
  (sun.awt.image.ImageFetcher)0x1               Image Animator 0  sleeping
  (java.lang.Thread)0x0                         Intro             running
> thread 0x7
Java2D Disposer[1] where
  [1] java.lang.Object.wait (native method)
  [2] java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:116)
  [3] java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:132)
  [4] sun.java2d.Disposer.run (Disposer.java:125)
  [5] java.lang.Thread.run (Thread.java:619)
Java2D Disposer[1] up 1
Java2D Disposer[2] where
  [2] java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:116)
  [3] java.lang.ref.ReferenceQueue.remove (ReferenceQueue.java:132)
  [4] sun.java2d.Disposer.run (Disposer.java:125)
  [5] java.lang.Thread.run (Thread.java:619)

この例では、threads コマンドを使ってすべてのスレッドの一覧を取得しています。 次に、thread 0x7 コマンドで特定のスレッドを選択し、where コマンドを使ってスレッドダンプを取得しています。次に、up 1 コマンドを使ってスタック内で 1 フレーム上に移動し、where コマンドを再度使ってスレッドダンプを取得しています。

2.4.2 同一マシン上のコアファイルへの接続

デバッガをコアファイルに接続するには、SA コア接続コネクタを使用します。コアファイルはクラッシュ後に作成された可能性があります (「第 4 章「システムクラッシュのトラブルシューティング」を参照)。コアファイルは、Solaris OS では gcore コマンド、Linux では gdbgcore コマンドを使って取得することもできます。コアファイルはコアファイル作成時のプロセスのスナップショットなので、コネクタは読み取り専用モードで接続します。デバッガは、クラッシュ時のスレッドや実行中アプリケーションを検査できます。

次のコマンドは、このコネクタの使用例です。

$ jdb -connect sun.jvm.hotspot.jdi.SACoreAttachingConnector:\ javaExecutable=$JAVA_HOME/bin/java,core=core.20441

このコマンドは、sun.jvm.hotspot.jdi.SACoreAttachingConnector という名前のコネクタを使用するように jdb に指示しています。このコネクタは javaExecutablecore という名前の 2 つの引数を取ります。javaExecutable 引数は Java バイナリの名前を示します。core 引数は、コアファイル名 (この例では PID 20441 のプロセスからのコア) です。

2.4.3 別のマシン上のコアファイルまたはハングアッププロセスへの接続

別のマシンからトランスポートされたコアファイルをデバッグするには、OS のバージョンとライブラリが一致する必要があります。この場合はまず、SA デバッグサーバーという名前のプロキシサーバーを実行できます。その後、デバッガがインストールされたマシン上で、SA デバッグサーバー接続コネクタを使ってデバッグサーバーに接続できます。

下の例ではマシン 1、マシン 2 という 2 つのマシンがあります。マシン 1 でコアファイルが使用可能、マシン 2 でデバッガが使用可能です。次のようにマシン 1 で SA デバッグサーバーが起動されます。

$ jsadebugd $JAVA_HOME/bin/java core.20441

jsadebugd コマンドは 2 つの引数を取ります。最初の引数は実行可能ファイルの名前です。これはほとんどの場合 java ですが、別の名前のこともあります (埋め込み VM の場合など)。2 番目の引数は、コアファイルの名前です。この例でのコアファイルは、gcore ユーティリティーを使って PID 20441 のプロセスに対して取得されました。

マシン 2 上で次のコマンドのようにして、SA デバッグサーバー接続コネクタを使ってデバッガはリモートの SA デバッグサーバーに接続します。

$ jdb -connect sun.jvm.hotspot.jdi.SADebugServerAttachingConnector:\ debugServerName=machine1

このコマンドは、sun.jvm.hotspot.jdi.SADebugServerAttachingConnector という名前のコネクタを使用するように jdb に指示しています。このコネクタは、debugServerName という引数 (SA デバッグサーバーが実行されているマシンのホスト名または IP アドレス) を 1 つ持ちます。

SA デバッグサーバーはハングアッププロセスのリモートデバッグにも使用できます。その場合、単一の引数 (プロセスのプロセス ID) を取ります。さらに、同じマシン上で複数のデバッグサーバーを実行する必要がある場合は、それぞれに一意の ID を指定する必要があります。SA デバッグサーバー接続コネクタで、この ID は追加のコネクタ引数として提供されます。これらの詳細については、JPDA のドキュメントを参照してください。

2.5 jhat ユーティリティー

jhat ツールは、ヒープスナップショット内のオブジェクトトポロジを参照するための便利な手段を提供します。このツールは、Heap Analysis Tool (HAT) を置き換えるために JDK 6 リリースで導入されました。

jhat ユーティリティーの詳細については、jhat (Java Heap Analysis Tool) のマニュアルページを参照してください。

このツールは、バイナリ形式のヒープダンプ (jmap -dump で生成されたヒープダンプなど) を解析します。

このユーティリティーは、意図しないオブジェクト保持のデバッグに役立つ可能性があります。この用語は、もう不要になっているけれども、ルートセットからの一部のパス経由での参照のためにライブに保たれているオブジェクトを記述するために使用されます。これは、オブジェクトが不要になったあともオブジェクトへの意図しない静的参照が残っている場合、Observer や Listener で不要になった対象からの登録解除が失敗した場合、オブジェクトを参照している Thread が終了すべきときに終了しない場合などに発生することがあります。意図しないオブジェクト保持は、Java 言語ではメモリーリークに相当します。

このツールには標準クエリーがいくつか用意されています。たとえば、ルートセットから指定されたオブジェクトまでのすべての参照パスを表示する「ルート」クエリーは、不要なオブジェクト保持の発見に特に役立ちます。

標準クエリーに加え、Object Query Language (OQL) インタフェースで独自のカスタムクエリーを開発することもできます。

jhat コマンドを発行すると、このユーティリティーにより、指定された TCP ポート上で HTTP サーバーが起動されます。その後、任意のブラウザを使ってサーバーに接続し、指定したヒープダンプに対してクエリーを実行できます。

次の例では、jhat を実行して snapshot.hprof という名前のヒープダンプファイルを分析する方法を示しています。

$ jhat snapshot.hprof
Started HTTP server on port 7000
Reading from java_pid2278.hprof...
Dump file created Fri May 19 17:18:38 BST 2006
Snapshot read, resolving...
Resolving 6162194 objects...
Chasing references, expect 12324 dots................................
Eliminating duplicate references.....................................
Snapshot resolved.
Server is ready.

この時点で jhat により、ポート 7000 上で HTTP サーバーが起動されています。ブラウザを http://localhost:7000 にポイントして jhat サーバーに接続します。

サーバーに接続されたら、標準クエリー (次のサブセクションを参照) を実行したり、OQL クエリー (「2.5.2 カスタムクエリー」を参照) を作成したりできます。「すべてのクラス」クエリーがデフォルトで表示されます。

2.5.1 標準クエリー

これらのサブセクションでは標準クエリーについて説明します。

2.5.1.1 「すべてのクラス」クエリー

デフォルトページの「すべてのクラス」クエリーには、ヒープ内に存在しているすべてのクラス (プラットフォームクラスは除く) が表示されます。このリストは完全修飾クラス名でソートされ、パッケージ別に分けられます。クラスの名前をクリックすると、「クラス」クエリーに移動します。

このクエリーの 2 番目のバリアントには、プラットフォームクラスが含まれます。プラットフォームクラスには、完全修飾名が javasun.javax.swing.char[ などの接頭辞で始まるクラスが含まれます。この接頭辞のリストは、resources/platform_names.txt という名前のシステムリソースファイルに含まれています。このリストをオーバーライドするには、JAR ファイル内でリストを置き換えるか、または jhat の呼び出し時にクラスパス上で置換が先に発生するように調整してください。

2.5.1.2 「クラス」クエリー

「クラス」クエリーには、クラスに関する情報が表示されます。これにはスーパークラス、サブクラス、インスタンスデータメンバー、静的データメンバーが含まれます。このページから、任意の参照先クラスに移動したり、「インスタンス」クエリーに移動したりできます。

2.5.1.3 「オブジェクト」クエリー

「オブジェクト」クエリーでは、ヒープ上にあったオブジェクトに関する情報が提供されます。ここから、オブジェクトのクラスに移動したり、オブジェクトのオブジェクトメンバーの値に移動したりできます。現在のオブジェクトを参照しているオブジェクトに移動することもできます。おそらくもっとも価値の高いクエリーは、末尾にある「ルート」クエリー (「ルートセットからの参照チェーン」) です。

オブジェクトクエリーでは、オブジェクト割り当て時点でのスタックバックトレースも提供されます。

2.5.1.4 「インスタンス」クエリー

インスタンスクエリーでは、特定のクラスのすべてのインスタンスが表示されます。allInstances バリアントには、特定クラスのサブクラスのインスタンスも含まれます。ここから、元のクラスに戻ったり、いずれかのインスタンスの「オブジェクト」クエリーに移動したりできます。

2.5.1.5 「ルート」クエリー

「ルート」クエリーには、ルートセットから特定のオブジェクトまでの参照チェーンが表示されます。これは、特定のオブジェクトに到達可能なルートセットの各メンバーに 1 つのチェーンを提供します。このツールではこれらのチェーンの計算時に深さ優先探索が行われるため、最小長の参照チェーンが提供されます。

「ルート」クエリーには 2 つの種類があります。弱参照を除外するもの (「ルート」) と弱参照を含めるもの (「すべてのルート」) です。弱参照とは、その参照先がファイナライズ可能となり、ファイナライズされてから回収されるのを妨げない参照オブジェクトのことです。弱参照だけから参照されているオブジェクトは通常、保持されているとはみなされません (その領域が必要になった時点ですぐにガベージコレクタが収集できるため)。

これはおそらく、意図しないオブジェクト保持をデバッグするうえで、jhat でもっとも価値の高いクエリーです。保持されているオブジェクトを見つけたら、このクエリーで保持されている理由がわかります。

2.5.1.6 「到達可能なオブジェクト」クエリー

このクエリーは「オブジェクト」クエリーからアクセス可能であり、特定のオブジェクトから到達可能なすべてのオブジェクトの推移閉包を表示します。このリストはサイズの降順 (各サイズ内ではアルファベット順) にソートされます。末尾には、すべての到達可能オブジェクトの合計サイズが表示されます。これは、少なくともオブジェクトのトポロジが単純なシステムでは、メモリー内でのオブジェクトの実行時フットプリント合計を決定する際に役立つ可能性があります。

このクエリーの価値がもっとも高まるのは、-exclude コマンド行オプションと組み合わせて使用する場合です。これは、分析対象のオブジェクトが Observable である場合などに役立ちます。デフォルトではすべての Observer が到達可能となり、それらが合計サイズにカウントされます。-exclude オプションを使えば、データメンバー java.util.Observable.obsjava.util.Observable.arr を除外できます。

2.5.1.7 「すべてのクラスのインスタンス数」クエリー

このクエリーでは、システム内のプラットフォームクラス以外のすべてのクラスのインスタンス数が表示されます。そのソート順は、インスタンス数の降順になります。意図しないオブジェクト保持の問題を突きとめる良い方法は、プログラムをさまざまな入力で長時間実行したあと、ヒープダンプを要求することです。すべてのクラスのインスタンス数を確認すると、インスタンス数が予想より多いクラスがいくつかあることに気づく場合があります。その場合はそれらを (おそらく「ルート」クエリーを使って) 分析し、保持されている理由を確認できます。このクエリーのバリアントには、プラットフォームクラスが含まれます。

プラットフォームクラスについては、「すべてのクラス」クエリーのセクションで定義しています。

2.5.1.8 「すべてのルート」クエリー

このクエリーでは、弱参照を含むルートセットのすべてのメンバーが表示されます。

2.5.1.9 「新規インスタンス」クエリー

「新規インスタンス」クエリーは、2 つのヒープダンプ付きで jhat サーバーを呼び出した場合にのみ利用できます。このクエリーは「インスタンス」クエリーに似ていますが、新しいインスタンスだけを表示する点が異なります。インスタンスは、それが 2 番目のヒープダンプ内にあり、かつ同じ ID を持つ同じ型のオブジェクトがベースラインヒープダンプ内にない場合に、新規とみなされます。オブジェクトの ID は、オブジェクトを一意に識別する 32 ビットまたは 64 ビットの整数です。

2.5.1.10 ヒストグラムクエリー

組み込みヒストグラムおよびファイナライザヒストグラムクエリーも、役立つ情報を提供します。

2.5.2 カスタムクエリー

組み込み Object Query Language (OQL) インタフェースで独自のカスタムクエリーを開発できます。最初のページの「OQL クエリーの実行」ボタンをクリックすると OQL クエリーページが表示され、そこでカスタムクエリーを作成して実行できます。OQL のヘルプ機能では、組み込み関数が例付きで説明されます。

select 文の構文は次のとおりです。

select JavaScript-expression-to-select
   [ from [instanceof] classname identifier
   [ where JavaScript-boolean-expression-to-filter ] ]

次は select 文の例です。

select s from java.lang.String s where s.count >= 100

2.5.3 ヒープ分析のヒント

jhat から有用な情報を得るには、アプリケーションのある程度の知識に加え、そこで使用されているライブラリや API に関するある程度の知識も要求されることがよくあります。とはいえ、一般にこのツールを使えば、次の 2 つの重要な質問に答えることができます。

2.5.3.1 何がオブジェクトをライブに保っているのか。

オブジェクトインスタンスを表示しているときに、「このオブジェクトへの参照」というタイトルのセクションに一覧表示されているオブジェクトをチェックすれば、このオブジェクトを直接参照しているオブジェクトを確認できます。より重要なことは、「ルート」クエリーを使ってルートセットから特定のオブジェクトまでの参照チェーンを確認することです。これらの参照チェーンは、ルートオブジェクトからこのオブジェクトへのパスを示します。これらのチェーンがあれば、どのようにすればルートセットからオブジェクトに到達できるかをすばやく確認できます。

前述したように、「ルート」クエリーには 2 つの種類があります。弱参照を除外するもの (「ルート」) と弱参照を含めるもの (「すべてのルート」) です。弱参照とは、その参照先がファイナライズ可能となり、ファイナライズされてから回収されるのを妨げない参照オブジェクトのことです。弱参照だけから参照されているオブジェクトは通常、保持されているとはみなされません (その領域が必要になった時点ですぐにガベージコレクタが収集できるため)。

jhat ツールは、ルートセット参照チェーンを、ルートの種類に基づいて次の順序でソートします。

2.5.3.2 このオブジェクトはどこで割り当てられたのか。

オブジェクトインスタンスが表示されている場合、オブジェクトの割り当て元を示すタイトルのセクションに、スタックトレースの形式で割り当てサイトが表示されます。このようにして、オブジェクトがどこで作成されたかを確認できます。

この割り当てサイトの情報は、HPROF で heap=all オプションを使用してヒープダンプが作成された場合にのみ入手できます。この HPROF オプションには heap=dump オプションと heap=sites オプションの両方が含まれます。

単一のオブジェクトダンプを使ってリークを特定できない場合の別のアプローチは、一連のダンプを収集し、各ダンプの合間に作成されたオブジェクトに焦点を絞ることです。jhat ツールでは -baseline オプションを使ってこの機能が提供されています。

2 つのダンプが HPROF によって同じ VM インスタンスから生成された場合、-baseline オプションを使えばそれらを比較できます。同じオブジェクトがどちらのダンプにも現れる場合、それは報告される新規オブジェクトのリストから除外されます。1 つのダンプがベースラインとして指定され、そのベースラインの取得以降に 2 番目のダンプで作成されたオブジェクトに分析を集中できます。

次の例ではベースラインの指定方法を示します。

$ jhat -baseline snapshot.hprof#1 snapshot.hprof#2

上の例では、2 つのダンプはファイル snapshot.hprof 内にあり、それらは #1#2 をファイル名の末尾に付加することによって区別されます。

2 つのヒープダンプ付きで jhat が起動された場合、「すべてのクラスのインスタンス数」クエリーに、その型の新規オブジェクト数である追加列が含まれます。インスタンスは、それが 2 番目のヒープダンプ内にあり、かつ同じ ID を持つ同じ型のオブジェクトがベースライン内にない場合に、新規とみなされます。新規カウントをクリックすると、jhat はその型の新しいオブジェクトを一覧表示します。このときインスタンスごとに、それがどこで割り当てられたか、これらの新規オブジェクトが参照しているオブジェクト、および新規オブジェクトを参照しているほかのオブジェクトを表示できます。

一般に、-baseline オプションは、識別する必要のあるオブジェクトが連続するダンプの合間に作成されたに、非常に役立つ可能性があります。

2.6 jinfo ユーティリティー

jinfo コマンド行ユーティリティーは、実行中の Java プロセスまたはクラッシュダンプから構成情報を取得し、仮想マシンの起動時に使用されたシステムプロパティーまたはコマンド行フラグを出力します。

このユーティリティーは、jsadebugd デーモンを使ってリモートマシン上のプロセスやコアファイルを照会することもできます。この場合、出力により長い時間がかかります。

このユーティリティーの -flag オプションを使えば、指定された Java プロセスの特定の Java VM フラグの値を動的に設定、設定解除、または変更できます。「B.1.1 フラグ値の動的変更」を参照してください。

jinfo ユーティリティーの詳細については、マニュアルページを参照してください。

次は、Java プロセスからの出力例です。

$ jinfo 29620
Attaching to process ID 29620, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 1.6.0-rc-b100
Java System Properties:

java.runtime.name = Java(TM) SE Runtime Environment
sun.boot.library.path = /usr/jdk/instances/jdk1.6.0/jre/lib/sparc
java.vm.version = 1.6.0-rc-b100
java.vm.vendor = Sun Microsystems Inc.
java.vendor.url = http://java.sun.com/
path.separator = :
java.vm.name = Java HotSpot(TM) Client VM
file.encoding.pkg = sun.io
sun.java.launcher = SUN_STANDARD
sun.os.patch.level = unknown
java.vm.specification.name = Java Virtual Machine Specification
user.dir = /home/js159705
java.runtime.version = 1.6.0-rc-b100
java.awt.graphicsenv = sun.awt.X11GraphicsEnvironment
java.endorsed.dirs = /usr/jdk/instances/jdk1.6.0/jre/lib/endorsed
os.arch = sparc
java.io.tmpdir = /var/tmp/
line.separator =

java.vm.specification.vendor = Sun Microsystems Inc.
os.name = SunOS
sun.jnu.encoding = ISO646-US
java.library.path = /usr/jdk/instances/jdk1.6.0/jre/lib/sparc/client:/usr/jdk/instances/jdk1.6.0/jre/lib/sparc:
/usr/jdk/instances/jdk1.6.0/jre/../lib/sparc:/net/gtee.sfbay/usr/sge/sge6/lib/sol-sparc64:
/usr/jdk/packages/lib/sparc:/lib:/usr/lib
java.specification.name = Java Platform API Specification
java.class.version = 50.0
sun.management.compiler = HotSpot Client Compiler
os.version = 5.10
user.home = /home/js159705
user.timezone = US/Pacific
java.awt.printerjob = sun.print.PSPrinterJob
file.encoding = ISO646-US
java.specification.version = 1.6
java.class.path = /usr/jdk/jdk1.6.0/demo/jfc/Java2D/Java2Demo.jar
user.name = js159705
java.vm.specification.version = 1.0
java.home = /usr/jdk/instances/jdk1.6.0/jre
sun.arch.data.model = 32
user.language = en
java.specification.vendor = Sun Microsystems Inc.
java.vm.info = mixed mode, sharing
java.version = 1.6.0-rc
java.ext.dirs = /usr/jdk/instances/jdk1.6.0/jre/lib/ext:/usr/jdk/packages/lib/ext
sun.boot.class.path = /usr/jdk/instances/jdk1.6.0/jre/lib/resources.jar:
/usr/jdk/instances/jdk1.6.0/jre/lib/rt.jar:/usr/jdk/instances/jdk1.6.0/jre/lib/sunrsasign.jar:
/usr/jdk/instances/jdk1.6.0/jre/lib/jsse.jar:
/usr/jdk/instances/jdk1.6.0/jre/lib/jce.jar:/usr/jdk/instances/jdk1.6.0/jre/lib/charsets.jar:
/usr/jdk/instances/jdk1.6.0/jre/classes
java.vendor = Sun Microsystems Inc.
file.separator = /
java.vendor.url.bug = http://java.sun.com/cgi-bin/bugreport.cgi
sun.io.unicode.encoding = UnicodeBig
sun.cpu.endian = big
sun.cpu.isalist =

VM Flags:

ターゲット Java VM を -classpath および -Xbootclasspath 引数付きで起動した場合、jinfo の出力に java.class.pathsun.boot.class.path の設定が含まれます。この情報は、クラスローダーの問題を調査する際に必要となる可能性があります。

jinfo ツールは、プロセスから情報を取得するだけでなく、コアファイルを入力として使用できます。Solaris OS の場合、たとえば gcore ユーティリティーを使えば、上の例のプロセスのコアファイルを取得できます。コアファイルの名前は core.29620 となり、プロセスの作業ディレクトリ内に生成されます。次の例のように、Java 実行可能ファイルとコアファイルへのパスを、jinfo ユーティリティーの引数として指定する必要があります。

$ jinfo $JAVA_HOME/bin/java core.29620

バイナリ名は java でないことがあります。これは、JNI 呼び出し API を使って VM が作成されたときに発生します。jinfo ツールでは、コアファイルの生成元のバイナリが必要です。

2.7 jmap ユーティリティー

jmap コマンド行ユーティリティーは、実行中の VM またはコアファイルのメモリー関係の統計を出力します。

このユーティリティーは、jsadebugd デーモンを使ってリモートマシン上のプロセスやコアファイルを照会することもできます。この場合、出力により長い時間がかかります。

プロセスまたはコアファイルでコマンド行オプションなしで jmap を使用された場合、ロードされた共有オブジェクトの一覧が出力されます (出力は Solaris OS の pmap ユーティリティーに似ています)。より詳細な情報を得るために、オプション -heap-histo、または -permstat を使用できます。これらのオプションについては、以降の各サブセクションで説明します。

さらに、JDK 7 リリースで導入された -dump:format=b,file=filename オプションを使用すると、jmap によって、Java ヒープがバイナリ HPROF 形式で指定されたファイルにダンプされます。その後、jhat ツールを使ってこのファイルを解析できます。

jmap pid コマンドがハングアッププロセスのために応答しない場合、-F オプション (Solaris OS および Linux の場合のみ) を使って Serviceability Agent の使用を強制できます。

jmap ユーティリティーの詳細については、マニュアルページを参照してください。

2.7.1 ヒープの構成と使用量

次の Java ヒープ情報を取得するために、-heap オプションが使用されます。

次の例は、jmap -heap コマンドの出力を示しています。

$ jmap -heap 29620
Attaching to process ID 29620, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 1.6.0-rc-b100

using thread-local object allocation.
Mark Sweep Compact GC

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 67108864 (64.0MB)
   NewSize          = 2228224 (2.125MB)
   MaxNewSize       = 4294901760 (4095.9375MB)
   OldSize          = 4194304 (4.0MB)
   NewRatio         = 8
   SurvivorRatio    = 8
   PermSize         = 12582912 (12.0MB)
   MaxPermSize      = 67108864 (64.0MB)

Heap Usage:
New Generation (Eden + 1 Survivor Space):
   capacity = 2031616 (1.9375MB)
   used     = 70984 (0.06769561767578125MB)
   free     = 1960632 (1.8698043823242188MB)
   3.4939673639112905% used
Eden Space:
   capacity = 1835008 (1.75MB)
   used     = 36152 (0.03447723388671875MB)
   free     = 1798856 (1.7155227661132812MB)
   1.9701276506696428% used
From Space:
   capacity = 196608 (0.1875MB)
   used     = 34832 (0.0332183837890625MB)
   free     = 161776 (0.1542816162109375MB)
   17.716471354166668% used
To Space:
   capacity = 196608 (0.1875MB)
   used     = 0 (0.0MB)
   free     = 196608 (0.1875MB)
   0.0% used
tenured generation:
   capacity = 15966208 (15.2265625MB)
   used     = 9577760 (9.134063720703125MB)
   free     = 6388448 (6.092498779296875MB)
   59.98769400974859% used
Perm Generation:
   capacity = 12582912 (12.0MB)
   used     = 1469408 (1.401336669921875MB)
   free     = 11113504 (10.598663330078125MB)
   11.677805582682291% used

2.7.2 実行中のプロセスのヒープヒストグラム

-histo オプションを使って、クラス単位のヒープヒストグラムを取得できます。

実行中のプロセスに対してコマンドが実行されると、ツールはクラスごとにオブジェクト数、メモリーサイズ (バイト)、および完全修飾クラス名を出力します。HotSpot VM の内部クラスは山括弧で囲まれます。ヒストグラムは、ヒープがどのように使われているかを理解するのに役立ちます。オブジェクトのサイズを得るには、合計サイズをそのオブジェクト型の数で割る必要があります。

次の例は、jmap -histo コマンドをプロセスに対して実行した場合の出力を示しています。

$ jmap -histo 29620
num   #instances    #bytes  class name
--------------------------------------
  1:      1414     6013016  [I
  2:       793      482888  [B
  3:      2502      334928  <constMethodKlass>
  4:       280      274976  <instanceKlassKlass>
  5:       324      227152  [D
  6:      2502      200896  <methodKlass>
  7:      2094      187496  [C
  8:       280      172248  <constantPoolKlass>
  9:      3767      139000  [Ljava.lang.Object;
 10:       260      122416  <constantPoolCacheKlass>
 11:      3304      112864  <symbolKlass>
 12:       160       72960  java2d.Tools$3
 13:       192       61440  <objArrayKlassKlass>
 14:       219       55640  [F
 15:      2114       50736  java.lang.String
 16:      2079       49896  java.util.HashMap$Entry
 17:       528       48344  [S
 18:      1940       46560  java.util.Hashtable$Entry
 19:       481       46176  java.lang.Class
 20:        92       43424  javax.swing.plaf.metal.MetalScrollButton
... more lines removed here to reduce output...
1118:         1           8  java.util.Hashtable$EmptyIterator
1119:         1           8  sun.java2d.pipe.SolidTextRenderer
Total    61297    10152040

2.7.3 コアファイルのヒープヒストグラム

コアファイルに対して jmap -histo コマンドが実行された場合、ツールはクラスごとにサイズ、カウント、クラス名を出力します。HotSpot VM の内部クラスには、先頭にアスタリスク (*) が付けられます。

& jmap -histo /net/koori.sfbay/onestop/jdk/6.0/promoted/all/b100/binaries/ solaris-sparcv9/bin/java core
Attaching to core core from executable /net/koori.sfbay/onestop/jdk/6.0/
promoted/all/b100/binaries/solaris-sparcv9/bin/java, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 1.6.0-rc-b100
Iterating over heap. This may take a while...
Heap traversal took 8.902 seconds.

Object Histogram:

Size    Count    Class description
-------------------------------------------------------
4151816    2941    int[]
2997816    26403    * ConstMethodKlass
2118728    26403    * MethodKlass
1613184    39750    * SymbolKlass
1268896    2011    * ConstantPoolKlass
1097040    2011    * InstanceKlassKlass
882048    1906    * ConstantPoolCacheKlass
758424    7572    char[]
733776    2518    byte[]
252240    3260    short[]
214944    2239    java.lang.Class
177448    3341    * System ObjArray
176832    7368    java.lang.String
137792    3756    java.lang.Object[]
121744    74    long[]
72960    160    java2d.Tools$3
63680    199    * ObjArrayKlassKlass
53264    158    float[]
... more lines removed here to reduce output...

2.7.4 Permanent 世代に関する情報の取得

Permanent 世代は、仮想マシン自体のすべてのリフレクションデータ (クラスオブジェクトやメソッドオブジェクトなど) を保持するヒープ領域です (Java 仮想マシン仕様では「メソッド領域」とも呼ばれる)。

非常に多くのクラスを動的に生成してロードするアプリケーション (Java Server Pages や Web コンテナなど) では、Permanent 世代のサイズの構成が重要になる可能性があります。アプリケーションでロードされたクラスが「多すぎた」場合、OutOfMemoryError でアプリケーションが異常終了する可能性があります。具体的なエラーは、Exception in thread XXXX java.lang.OutOfMemoryError: PermGen space です。OutOfMemoryError のこれの理由およびその他の理由については、「3.1 OutOfMemoryError の意味」を参照してください。

Permanent 世代に関する詳細情報を得るために、-permstat オプションを使って Permanent 世代内のオブジェクトの統計を出力できます。次の例は、jmap -permstat コマンドの出力を示しています。

$ jmap -permstat 29620
Attaching to process ID 29620, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 1.6.0-rc-b100
12674 intern Strings occupying 1082616 bytes.
finding class loader instances ..Unknown oop at 0xd0400900
Oop's klass is 0xd0bf8408
Unknown oop at 0xd0401100
Oop's klass is null
done.
computing per loader stat ..done.
please wait.. computing liveness.........................................done.
class_loader    classes bytes   parent_loader   alive?  type

<bootstrap>     1846 5321080  null        live   <internal>
0xd0bf3828  0      0      null         live    sun/misc/Launcher$ExtClassLoader@0xd8c98c78
0xd0d2f370  1    904      null         dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0c99280  1   1440      null         dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0b71d90  0      0   0xd0b5b9c0    live java/util/ResourceBundle$RBClassLoader@0xd8d042e8
0xd0d2f4c0  1    904      null         dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0b5bf98  1    920   0xd0b5bf38      dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0c99248  1    904      null         dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0d2f488  1    904      null         dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0b5bf38  6   11832  0xd0b5b9c0      dead    sun/reflect/misc/MethodUtil@0xd8e8e560
0xd0d2f338  1    904      null         dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0d2f418  1    904      null         dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0d2f3a8  1    904     null          dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0b5b9c0  317 1397448 0xd0bf3828     live    sun/misc/Launcher$AppClassLoader@0xd8cb83d8
0xd0d2f300  1    904      null         dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0d2f3e0  1    904      null         dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0ec3968  1   1440      null         dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0e0a248  1    904      null         dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0c99210  1    904      null         dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0d2f450  1    904      null         dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0d2f4f8  1    904      null         dead    sun/reflect/DelegatingClassLoader@0xd8c22f50
0xd0e0a280  1    904      null         dead    sun/reflect/DelegatingClassLoader@0xd8c22f50

total = 22      2186    6746816   N/A   alive=4, dead=18       N/A    

クラスローダーオブジェクトごとに次の詳細が出力されます。

2.8 jps ユーティリティー

jps ユーティリティーは、ターゲットシステム上の現在のユーザーで計測された HotSpot 仮想マシンを一覧表示します。VM が埋め込まれた環境、つまり java 起動ツールではなく JNI 呼び出し API を使って VM が起動される環境では、このユーティリティーが非常に役立ちます。こうした環境では、プロセスリスト内で Java プロセスを認識するのが常に容易であるとはかぎりません。

次の例は、jps ユーティリティーの使用方法を示しています。

$ jps
16217 MyApplication
16342 jps

このユーティリティーは、ユーザーがアクセス権を持つ仮想マシンを一覧表示します。これは、オペレーティングシステム固有のアクセス制御メカニズムによって決定されます。Solaris OS 上でたとえば非 root ユーザーが jps ユーティリティーを実行した場合、出力はそのユーザーの uid で起動された仮想マシンの一覧です。

このユーティリティーには、プロセス ID の一覧表示に加え、アプリケーションの main メソッドに渡された引数、VM 引数の完全なリスト、アプリケーションの main クラスの完全なパッケージ名を出力するオプションも用意されています。また、リモートシステム上で jstat デーモン (jstatd) が実行されていれば、jps ユーティリティーはリモートシステム上のプロセスを一覧表示することもできます。

システム上でいくつかの Java Web Start アプリケーションを実行している場合、次の例に示すように、それらは同じに見えてしまいがちです。

$ jps
1271 jps
     1269 Main
     1190 Main

この場合、次のように jps -m を使ってそれらを区別します。

$ jps -m
1271 jps -m
     1269 Main http://bugster.central.sun.com/bugster.jnlp
     1190 Main http://webbugs.sfbay/IncidentManager/incident.jnlp

jps ユーティリティーの詳細については、マニュアルページを参照してください。

このユーティリティーは、Sun がサポートするすべてのオペレーティングシステムプラットフォームの JDK ダウンロードに含まれています。


注 - Windows 98 や Windows ME では HotSpot インストゥルメンテーションにアクセスできません。さらに、Windows で一時ディレクトリが FAT32 ファイルシステム上にある場合、インストゥルメンテーションにアクセスできない可能性があります。


2.9 jrunscript ユーティリティー

jrunscript ユーティリティーはコマンド行スクリプトシェルです。インタラクティブモード、バッチモードの両方のスクリプト実行がサポートされています。このシェルではデフォルトで JavaScript が使用されますが、ほかの任意のスクリプト言語を指定し、そのスクリプトエンジンの .class ファイル を含む JAR ファイルへのパスを指定できます。

jrunscript ユーティリティーでは、Java 言語とスクリプト言語間で通信が行われるため、探求的なプログラミングスタイルがサポートされています。

jrunscript ユーティリティーの詳細については、マニュアルページを参照してください。

2.10 jsadebugd デーモン

Serviceability Agent Debug Daemon (jsadebugd) は、Java プロセスまたはコアファイルに接続し、デバッグサーバーとして動作します。このユーティリティーは現在のところ、Solaris OS と Linux でのみ利用できます。jstackjmap および jinfo などのリモートクライアントは、Java Remote Method Invocation (RMI) を使用しているサーバーに接続できます。

jsadebugd ユーティリティーの詳細については、マニュアルページを参照してください。

2.11 jstack ユーティリティー

jstack コマンド行ユーティリティーは、指定されたプロセスまたはコアファイルに接続し、仮想マシンに接続されたすべてのスレッド (Java スレッドや VM 内部スレッドも含む) のスタックトレースを出力するほか、オプションでネイティブスタックフレームも出力します。このユーティリティーではデッドロック検出も実行されます。

このユーティリティーは、jsadebugd デーモンを使ってリモートマシン上のプロセスやコアファイルを照会することもできます。この場合、出力により長い時間がかかります。

すべてのスレッドのスタックトレースは、デッドロックやハングアップなど、いくつかの問題の診断に役立つ可能性があります。

JDK 7 リリースで導入された -l オプションは、所有可能なシンクロナイザをヒープ内で探して java.util.concurrent.locks に関する情報を出力するように、ユーティリティーに指示します。このオプションがない場合、スレッドダンプにはモニターの情報のみが含まれます。

JDK 7 以降、jstack pid オプションの出力は、アプリケーションコンソール (標準入力) で Ctrl-\ を押すかプロセスに QUIT シグナルを送信した場合に得られるものと同じです。出力例については、「2.15 Ctrl-Break ハンドラ」を参照してください。

スレッドダンプは、プログラム内で Thread.getAllStackTraces メソッドを使って、またはデバッガ内ですべてのスレッドスタックを出力するデバッガオプション (jdb サンプルデバッガの場合は where コマンド) を使って取得することもできます。

jstack ユーティリティーの詳細については、マニュアルページを参照してください。

2.11.1 スタックダンプの強制

jstack pid コマンドがハングアッププロセスのために応答しない場合、次の例のように -F オプション (Solaris OS および Linux の場合のみ) を使ってスタックダンプを強制できます。

$ jstack -F 8321
Attaching to process ID 8321, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 1.6.0-rc-b100
Deadlock Detection:

Found one Java-level deadlock:
=============================

"Thread2":
  waiting to lock Monitor@0x000af398 (Object@0xf819aa10, a java/lang/String),
  which is held by "Thread1"
"Thread1":
  waiting to lock Monitor@0x000af400 (Object@0xf819aa48, a java/lang/String),
  which is held by "Thread2"

Found a total of 1 deadlock.

Thread t@2: (state = BLOCKED)

Thread t@11: (state = BLOCKED)
 - Deadlock$DeadlockMakerThread.run() @bci=108, line=32 (Interpreted frame)

Thread t@10: (state = BLOCKED)
 - Deadlock$DeadlockMakerThread.run() @bci=108, line=32 (Interpreted frame)

Thread t@6: (state = BLOCKED)

Thread t@5: (state = BLOCKED)
 - java.lang.Object.wait(long) @bci=-1107318896 (Interpreted frame)
 - java.lang.Object.wait(long) @bci=0 (Interpreted frame)
 - java.lang.ref.ReferenceQueue.remove(long) @bci=44, line=116 (Interpreted frame)
 - java.lang.ref.ReferenceQueue.remove() @bci=2, line=132 (Interpreted frame)
 - java.lang.ref.Finalizer$FinalizerThread.run() @bci=3, line=159 (Interpreted frame)

Thread t@4: (state = BLOCKED)
 - java.lang.Object.wait(long) @bci=0 (Interpreted frame)
 - java.lang.Object.wait(long) @bci=0 (Interpreted frame)
 - java.lang.Object.wait() @bci=2, line=485 (Interpreted frame)
 - java.lang.ref.Reference$ReferenceHandler.run() @bci=46, line=116 (Interpreted frame)

2.11.2 コアダンプからのスタックトレースの出力

コアダンプからスタックトレースを取得するには、次のコマンドを実行します。

$ jstack $JAVA_HOME/bin/java core

2.11.3 混合スタックの出力

jstack ユーティリティーは、混合スタックの出力に使用することもできます (つまり、Java スタックのほかにネイティブスタックフレームも出力できます)。ネイティブフレームとは、VM コードや JNI/ネイティブコードに関連付けられた C/C++ フレームのことです。

混合スタックを出力するには、次の例のように -m オプションを使用します。

$ jstack -m 21177
Attaching to process ID 21177, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 1.6.0-rc-b100
Deadlock Detection:

Found one Java-level deadlock:
=============================

"Thread1":
  waiting to lock Monitor@0x0005c750 (Object@0xd4405938, a java/lang/String),
  which is held by "Thread2"
"Thread2":
  waiting to lock Monitor@0x0005c6e8 (Object@0xd4405900, a java/lang/String),
  which is held by "Thread1"

Found a total of 1 deadlock.

----------------- t@1 -----------------
0xff2c0fbc    __lwp_wait + 0x4
0xff2bc9bc    _thrp_join + 0x34
0xff2bcb28    thr_join + 0x10
0x00018a04    ContinueInNewThread + 0x30
0x00012480    main + 0xeb0
0x000111a0    _start + 0x108
----------------- t@2 -----------------
0xff2c1070    ___lwp_cond_wait + 0x4
0xfec03638    bool Monitor::wait(bool,long) + 0x420
0xfec9e2c8    bool Threads::destroy_vm() + 0xa4
0xfe93ad5c    jni_DestroyJavaVM + 0x1bc
0x00013ac0    JavaMain + 0x1600
0xff2bfd9c    _lwp_start
----------------- t@3 -----------------
0xff2c1070    ___lwp_cond_wait + 0x4
0xff2ac104    _lwp_cond_timedwait + 0x1c
0xfec034f4    bool Monitor::wait(bool,long) + 0x2dc
0xfece60bc    void VMThread::loop() + 0x1b8
0xfe8b66a4    void VMThread::run() + 0x98
0xfec139f4    java_start + 0x118
0xff2bfd9c    _lwp_start
----------------- t@4 -----------------
0xff2c1070    ___lwp_cond_wait + 0x4
0xfec195e8    void os::PlatformEvent::park() + 0xf0
0xfec88464    void ObjectMonitor::wait(long long,bool,Thread*) + 0x548
0xfe8cb974    void ObjectSynchronizer::wait(Handle,long long,Thread*) + 0x148
0xfe8cb508    JVM_MonitorWait + 0x29c
0xfc40e548    * java.lang.Object.wait(long) bci:0 (Interpreted frame)
0xfc40e4f4    * java.lang.Object.wait(long) bci:0 (Interpreted frame)
0xfc405a10    * java.lang.Object.wait() bci:2 line:485 (Interpreted frame)
... more lines removed here to reduce output...
----------------- t@12 -----------------
0xff2bfe3c    __lwp_park + 0x10
0xfe9925e4    AttachOperation*AttachListener::dequeue() + 0x148
0xfe99115c    void attach_listener_thread_entry(JavaThread*,Thread*) + 0x1fc
0xfec99ad8    void JavaThread::thread_main_inner() + 0x48
0xfec139f4    java_start + 0x118
0xff2bfd9c    _lwp_start
----------------- t@13 -----------------
0xff2c1500    _door_return + 0xc
----------------- t@14 -----------------
0xff2c1500    _door_return + 0xc

先頭に「*」が付いているフレームが Java フレーム、先頭に「*」が付いていないフレームがネイティブ C/C++ フレームです。

このユーティリティーの出力をパイプ経由で c++filt に渡せば、C++ の分解されたシンボル名を分解解除できます。HotSpot 仮想マシンは C++ 言語で開発されているので、jstack ユーティリティーは HotSpot 内部関数に対して C++ 分解シンボル名を出力します。c++filt ユーティリティーは、次のネイティブ c++ コンパイラスイートとともに配布されています。SUNWspro (Solaris OS) および gnu (Linux)。

2.12 jstat ユーティリティー

jstat ユーティリティーは、HotSpot VM の組み込みインストゥルメンテーションを使って、実行中アプリケーションのパフォーマンスやリソース消費に関する情報を提供します。このツールは、パフォーマンスの問題、特にヒープサイズ決定やガベージコレクションに関係する問題を診断するときに使用できます。jstat ユーティリティーでは、特殊なオプション付きで VM を起動する必要はありません。HotSpot VM の組み込みインストゥルメンテーションはデフォルトで有効になります。このユーティリティーは、Sun がサポートするすべてのオペレーティングシステムプラットフォームの JDK ダウンロードに含まれています。


注 - Windows 98 や Windows ME ではインストゥルメンテーションにアクセスできません。さらに、Windows NT、2000、または XP で FAT32 ファイルシステムが使用されている場合、インストゥルメンテーションにアクセスできません。


次のリストは、jstat ユーティリティーのオプションを示しています。

jstat ユーティリティーの完全な説明については、マニュアルページを参照してください。

ドキュメントにはいくつか例が含まれていて、それらのいくつかをこのドキュメントのここでそのまま掲載します。

jstat ユーティリティーは、vmid を使ってターゲットプロセスを識別します。vmid の構文はドキュメントに記載されていますが、もっとも単純な場合、vmid はローカル仮想マシン識別子になることができます。Solaris OS、Linux、および Windows の場合、これはプロセス ID とみなすことができます。これが標準的ですが、常にそうであるとはかぎりません。

jstat ツールで提供されるデータは、Solaris OS および Linux のツール vmstat および iostat で提供されるデータに似ています。

データをグラフィカルに表現する場合は、visualgc ツールを使用できます。「2.14 visualgc ツール」を参照してください。

2.12.1 -gcutil オプションの例

次は -gcutil オプションの例です。ユーティリティーは、lvmid 2834 に接続し、250 ミリ秒間隔で 9 つのサンプルを取り、出力を表示しています。

$ jstat -gcutil 2834 250 9
  S0     S1     E      O      P     YGC     YGCT    FGC    FGCT     GCT   
  0.00   0.00  87.14  46.56  96.82     54    1.197   140   86.559   87.757
  0.00   0.00  91.90  46.56  96.82     54    1.197   140   86.559   87.757
  0.00   0.00 100.00  46.56  96.82     54    1.197   140   86.559   87.757
  0.00  27.12   5.01  54.60  96.82     55    1.215   140   86.559   87.774
  0.00  27.12  11.22  54.60  96.82     55    1.215   140   86.559   87.774
  0.00  27.12  13.57  54.60  96.82     55    1.215   140   86.559   87.774
  0.00  27.12  18.05  54.60  96.82     55    1.215   140   86.559   87.774
  0.00  27.12  23.85  54.60  96.82     55    1.215   140   86.559   87.774
  0.00  27.12  27.32  54.60  96.82     55    1.215   140   86.559   87.774

この例の出力は、若い世代のコレクションが 3 番目と 4 番目のサンプル間で行われたことを示しています。コレクションには 0.017 秒かかっており、オブジェクトが eden 領域 (E) から Old 領域 (O) に昇格したため、old 領域の使用率は 46.56% から 54.60% に増加しています。

2.12.2 -gcnew オプションの例

次の例は、-gcnew オプションを示しています。ユーティリティーは、lvmid 2834 に接続し、250 ミリ秒間隔でサンプルを取り、出力を表示しています。さらに、-h3 オプションを使用して、データが 3 行表示されるごとに列ヘッダーを表示します。

$ jstat -gcnew -h3 2834 250
S0C    S1C    S0U    S1U   TT MTT  DSS      EC       EU     YGC     YGCT  
 192.0  192.0    0.0    0.0 15  15   96.0   1984.0    942.0    218    1.999
 192.0  192.0    0.0    0.0 15  15   96.0   1984.0   1024.8    218    1.999
 192.0  192.0    0.0    0.0 15  15   96.0   1984.0   1068.1    218    1.999
 S0C    S1C    S0U    S1U   TT MTT  DSS      EC       EU     YGC     YGCT  
 192.0  192.0    0.0    0.0 15  15   96.0   1984.0   1109.0    218    1.999
 192.0  192.0    0.0  103.2  1  15   96.0   1984.0      0.0    219    2.019
 192.0  192.0    0.0  103.2  1  15   96.0   1984.0     71.6    219    2.019
 S0C    S1C    S0U    S1U   TT MTT  DSS      EC       EU     YGC     YGCT  
 192.0  192.0    0.0  103.2  1  15   96.0   1984.0     73.7    219    2.019
 192.0  192.0    0.0  103.2  1  15   96.0   1984.0     78.0    219    2.019
 192.0  192.0    0.0  103.2  1  15   96.0   1984.0    116.1    219    2.019

この例では、ヘッダー文字列の繰り返しが見られるほかにも、4 番目と 5 番目のサンプル間で若い世代のコレクションが発生し、その継続時間が 0.02 秒だったことがわかります。このコレクションでは、Survivor 領域 0 の使用率 (S1U) が適切な Survivor サイズ (DSS) を超過するのに十分なライブデータが検出されました。この結果、オブジェクトは、Old 世代 (この出力には非表示) へ昇格され、殿堂入りしきい値 (TT) が、15 から 1 へ降格されました。

2.12.3 -gcoldcapacity オプションの例

次の例は、-gcoldcapacity オプションを示しています。ユーティリティーは、lvmid 21891 へ接続し、250 ミリ秒間隔で 3 つのサンプルを取得しています。-t オプションを使用して、最初の列にサンプルごとのタイムスタンプを表示しています。

$ jstat -gcoldcapacity -t 21891 250 3
Timestamp    OGCMN     OGCMX       OGC        OC   YGC   FGC     FGCT     GCT
    150.1   1408.0   60544.0   11696.0   11696.0   194    80    2.874   3.799
    150.4   1408.0   60544.0   13820.0   13820.0   194    81    2.938   3.863
    150.7   1408.0   60544.0   13820.0   13820.0   194    81    2.938   3.863

Timestamp 列には、ターゲット Java VM の起動時からの経過時間が、秒単位で報告されています。さらに、-gcoldcapacity 出力では、割り当て要求または昇格要求あるいはその両方を満たすためにヒープが拡張するごとに、Old 世代の容量 (OGC) と Old 領域の容量 (OC) とが増加していることがわかります。Old 世代の容量 (OGC) は、81 番目のフル GC (FGC) 後に、11696 K バイトから 13820 K バイトへ増加しています。Old 世代 (および領域) の最大容量は、60544 K バイト (OGCMX) なので、まだ拡張できる余裕が残されています。

2.13 jstatd デーモン

jstatd デーモンは、計測された Java HotSpot 仮想マシンの作成と終了をモニターし、ローカルシステム上で実行している Java VM にリモートモニタリングツールが接続することを許可するインタフェースを提供する、Remote Method Invocation (RMI) サーバーアプリケーションです。たとえば、このデーモンを使えば、jps ユーティリティーでリモートシステム上のプロセスを一覧表示できます。


注 - Windows 98 や Windows ME ではインストゥルメンテーションにアクセスできません。さらに、Windows NT、2000、または XP で FAT32 ファイルシステムが使用されている場合、インストゥルメンテーションにアクセスできません。


詳細な使用例など、jstatd デーモンの詳細については、マニュアルページを参照してください。

2.14 visualgc ツール

visualgc ツールは jstat ツールに関係しています。(「2.12 jstat ユーティリティー」を参照。)visualgc ツールは、ガベージコレクション (GC) システムのグラフィカル表示を提供します。これは jstat と同様に、HotSpot VM の組み込みインストゥルメンテーションを使用します。

visualgc ツールは JDK リリースには含まれていませんが、jvmstat 3.0 サイトから個別のダウンロードとして入手できます。

次の画面出力は、GC やヒープがどのように視覚化されるかを示しています。

visualgc からのサンプル出力
visualgc ツールからのサンプル出力画面

2.15 Ctrl-Break ハンドラ

Solaris OS または Linux の場合、アプリケーションコンソール (標準入力) で Ctrl キーとバックスラッシュ (\) キーの組み合わせを押すと、HotSpot VM からアプリケーションの標準出力にスレッドダンプが出力されます。Windows の場合、同等のキーシーケンスは Ctrl キーと Break キーです。これらのキーの組み合わせに対する一般的な用語は、Ctrl-Break ハンドラです。

Solaris OS および Linux の場合、Java プロセスが QUIT シグナルを受信すると、スレッドダンプが出力されます。したがって、kill -QUIT pid コマンドを実行すると、pid を ID に持つプロセスから標準出力にスレッドダンプが出力されます。

次の各サブセクションでは、Ctrl-Break ハンドラの出力について詳しく説明します。

2.15.1 スレッドダンプ

スレッドダンプは、仮想マシン内のすべての Java スレッドに対するスレッドスタック (スレッド状態を含む) から構成されます。スレッドダンプが出力されてもアプリケーションは終了しません。スレッド情報の出力後も継続されます。

次の例はスレッドダンプを示しています。

Full thread dump Java HotSpot(TM) Client VM (1.6.0-rc-b100 mixed mode):

"DestroyJavaVM" prio=10 tid=0x00030400 nid=0x2 waiting on condition [0x00000000..0xfe77fbf0]
   java.lang.Thread.State: RUNNABLE

"Thread2" prio=10 tid=0x000d7c00 nid=0xb waiting for monitor entry [0xf36ff000..0xf36ff8c0]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at Deadlock$DeadlockMakerThread.run(Deadlock.java:32)
        - waiting to lock <0xf819a938> (a java.lang.String)
        - locked <0xf819a970> (a java.lang.String)

"Thread1" prio=10 tid=0x000d6c00 nid=0xa waiting for monitor entry [0xf37ff000..0xf37ffbc0]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at Deadlock$DeadlockMakerThread.run(Deadlock.java:32)
        - waiting to lock <0xf819a970> (a java.lang.String)
        - locked <0xf819a938> (a java.lang.String)

"Low Memory Detector" daemon prio=10 tid=0x000c7800 nid=0x8 runnable [0x00000000..0x00000000]
   java.lang.Thread.State: RUNNABLE

"CompilerThread0" daemon prio=10 tid=0x000c5400 nid=0x7 waiting on condition [0x00000000..0x00000000]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x000c4400 nid=0x6 waiting on condition [0x00000000..0x00000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=10 tid=0x000b2800 nid=0x5 in Object.wait() [0xf3f7f000..0xf3f7f9c0]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0xf4000b40> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)
        - locked <0xf4000b40> (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=0x000ae000 nid=0x4 in Object.wait() [0xfe57f000..0xfe57f940]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0xf4000a40> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:485)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)
        - locked <0xf4000a40> (a java.lang.ref.Reference$Lock)

"VM Thread" prio=10 tid=0x000ab000 nid=0x3 runnable 

"VM Periodic Task Thread" prio=10 tid=0x000c8c00 nid=0x9 waiting on condition 

出力は、各スレッドのヘッダーとスタックトレースから構成されます。各スレッドは空行で区切られます。Java スレッド (Java 言語コードを実行できるスレッド) がまず出力され、それらのあとに VM 内部スレッドに関する情報が続きます。

ヘッダー行には、スレッドに関する次の情報が含まれます。

次の表に、出力される可能性のあるスレッド状態の一覧を示します。

スレッドの状態
意味
NEW
スレッドはまだ開始されていません。
RUNNABLE
スレッドが Java 仮想マシン内で実行中です。
BLOCKED
スレッドがモニターロックを待機してブロックされています。
WAITING
スレッドは、別のスレッドが特定のアクションを実行するのを無期限に待機中です。
TIMED_WAITING
スレッドは指定された待機時間、別のスレッドがアクションを実行するのを待機中です。
TERMINATED
スレッドは終了しています。

スレッドヘッダーのあとにスレッドスタックが続きます。

2.15.2 デッドロックの検出

Ctrl-Break ハンドラは、スレッドスタックだけでなく、デッドロック検出アルゴリズムを実行します。デッドロックが検出された場合、デッドロックされた各スレッドに関する追加情報がスレッドダンプのあとに出力されます。

Found one Java-level deadlock:
=============================
"Thread2":
  waiting to lock monitor 0x000af330 (object 0xf819a938, a java.lang.String),
  which is held by "Thread1"
"Thread1":
  waiting to lock monitor 0x000af398 (object 0xf819a970, a java.lang.String),
  which is held by "Thread2"

Java stack information for the threads listed above:
===================================================
"Thread2":
        at Deadlock$DeadlockMakerThread.run(Deadlock.java:32)
        - waiting to lock <0xf819a938> (a java.lang.String)
        - locked <0xf819a970> (a java.lang.String)
"Thread1":
        at Deadlock$DeadlockMakerThread.run(Deadlock.java:32)
        - waiting to lock <0xf819a970> (a java.lang.String)
        - locked <0xf819a938> (a java.lang.String)

Found 1 deadlock.

Java VM フラグ -XX:+PrintConcurrentLocks が設定されている場合、Ctrl-Break は各スレッドが所有している並行ロックのリストも出力します。

2.15.3 ヒープサマリー

JDK 7 以降、Ctrl-Break ハンドラはヒープサマリーも出力します。この出力では、さまざまな世代 (ヒープの領域) がそのサイズ、使用量、アドレス範囲とともに表示されます。アドレス範囲は特に、pmap などのツールでプロセスを調査する場合にも役立ちます。

Heap
 def new generation   total 1152K, used 435K [0x22960000, 0x22a90000, 0x22e40000
)
  eden space 1088K,  40% used [0x22960000, 0x229ccd40, 0x22a70000)
  from space 64K,   0% used [0x22a70000, 0x22a70000, 0x22a80000)
  to   space 64K,   0% used [0x22a80000, 0x22a80000, 0x22a90000)
 tenured generation   total 13728K, used 6971K [0x22e40000, 0x23ba8000, 0x269600
00)
   the space 13728K,  50% used [0x22e40000, 0x2350ecb0, 0x2350ee00, 0x23ba8000)
 compacting perm gen  total 12288K, used 1417K [0x26960000, 0x27560000, 0x2a9600
00)
   the space 12288K,  11% used [0x26960000, 0x26ac24f8, 0x26ac2600, 0x27560000)
    ro space 8192K,  62% used [0x2a960000, 0x2ae5ba98, 0x2ae5bc00, 0x2b160000)
    rw space 12288K,  52% used [0x2b160000, 0x2b79e410, 0x2b79e600, 0x2bd60000)

Java VM フラグ -XX:+PrintClassHistogram が設定されている場合、Ctrl-Break ハンドラはヒープヒストグラムを生成します。

2.16 オペレーティングシステム固有のツール

このセクションでは、トラブルシューティングやモニタリング目的に役立ついくつかのオペレーティングシステム固有ツールの一覧を示します。各ツールについて簡単な説明が提供されます。詳細については、オペレーティングシステムのドキュメント (Solaris OS や Linux の場合はマニュアルページ) を参照してください。

2.16.1 Solaris オペレーティングシステム

次のツールは、Solaris オペレーティングシステムで提供されます。「2.16.4 Solaris 10 OS で導入されたツール」も参照してください (バージョン 10 の Solaris OS で導入されたいくつかのツールの詳細が提供されます)。

ツール
説明
coreadm
Java VM によって生成されるコアファイルの名前と場所を指定します。
cpustat
CPU パフォーマンスカウンタを使ってシステム動作をモニターします。
cputrack
CPU パフォーマンスカウンタを使ってプロセス、LWP の動作をプロセス単位でモニターします。
c++filt
C++ 分解シンボル名を分解解除します。このユーティリティーは、次のネイティブ c++ コンパイラスイートとともに配布されます。Solaris OS 上の SUNWspro
DTrace ツール

dtrace コマンド

Solaris 10 OS で導入: カーネル関数、システムコール、およびユーザー関数の動的トレース。このツールを使えば、入口、出口、およびその他のプローブポイントで任意の安全なスクリプトを実行できます。スクリプトは、D プログラミング言語と呼ばれる、C に似ているが安全なポインタセマンティクス言語で記述されます。「2.16.4.3 DTrace ツールの使用」も参照してください。
gcore
プロセスのコアダンプを強制します。コアダンプの書き込み後、プロセスは継続します。
intrstat
割り込みスレッドで消費される CPU に関する統計を報告します。
iostat
I/O 統計を報告します。
libumem
Solaris 9 OS Update 3 で導入: ユーザー領域スラブアロケータ。このツールを使えば、メモリー管理上のバグを発見して修正できます (「3.4.5 libumem を使ったリークの検出」を参照)。
mdb
カーネルおよびユーザーアプリケーションとクラッシュダンプ用のモジュラーデバッガ
netstat
各種ネットワーク関連データ構造体の内容を表示します。
pargs
プロセス引数、環境変数、または補助ベクトルを出力します。ほかのコマンド (ps など) のように、長い出力が切り詰められることはありません。
pfiles
プロセスファイル記述子に関する情報を出力します。Solaris 10 OS 以降、このツールはファイル名も出力します。
pldd
プロセスによってロードされた共有オブジェクトを出力します。
pmap
プロセスまたはコアファイルのメモリーレイアウト (ヒープ、データ、テキストセクションを含む) を出力します。Solaris 10 OS 以降は、スタックセグメントがテキスト [stack] とスレッド ID で明確に識別されます。「2.16.4.1 pmap ツールの改善」も参照してください。
prstat
アクティブな Solaris OS プロセスの統計を報告します。(top に似ています)。
prun
プロセスを実行モードに設定します (pstop の逆)。
ps
すべてのプロセスを一覧表示します。
psig
プロセスのシグナルハンドラを一覧表示します。
pstack
特定のプロセスまたはコアファイルのスレッドのスタックを出力します。Solaris 10 OS 以降は、Java フレームで Java メソッド名を出力できます。「2.16.4.2 pstack ツールの改善」も参照してください。
pstop
プロセスを停止 (中断) します。
ptree
指定された pid を含むプロセスツリーを出力します。
sar
システムアクティビティーレポータ。
sdtprocess
CPU 負荷が非常に高いプロセスを表示します。(top に似ています)。
sdtperfmeter
システムパフォーマンス (CPU、ディスク、ネットワークなど) を示すグラフを表示します。
top
CPU 負荷が非常に高いプロセスを表示します。このツールは、Solaris OS ではフリーウェアとして利用可能ですが、デフォルトではインストールされません。
trapstat
実行時トラップ統計を表示します。(SPARC のみ)
truss
システムコール、ユーザーモード関数、およびシグナルの開始/終了イベントをトレースします。必要に応じてこれらのイベントのいずれかでプロセスを停止します。このツールはシステムコールやユーザー関数の引数も出力します。
vmstat
システム仮想メモリーの統計を報告します。
watchmalloc
メモリー割り当てを追跡します。

2.16.2 Linux オペレーティングシステム

次のツールは、Linux オペレーティングシステムで提供されます。

ツール
説明
c++filt
C++ 分解シンボル名を分解解除します。このユーティリティーは、次のネイティブ c++ コンパイラスイートとともに配布されます。Linux OS 上の gnu
gdb
GNU デバッガ。
libnjamd
メモリー割り当ての追跡。
lsstack
スレッドスタックを出力します (Solaris OS の pstack に似ています)。

このツールは、すべてのディストリビューションがデフォルトで提供しているわけではありません。したがって、sourceforge.net Web サイトからダウンロードしなければいけない場合があります。

ltrace
ライブラリ呼び出しトレーサ (Solaris OS の truss -u と同等)。

このツールは、すべてのディストリビューションがデフォルトで提供しているわけではありません。したがって、別途ダウンロードしなければいけない場合があります。

mtrace および muntrace
GNU malloc トレーサ。
pmappstack などの proc ツール
Solaris OS 上の proc ツールの一部 (全部ではない) は、Linux 上に同等のツールを持っています。さらに、コアファイルサポートは Solaris OS の場合ほど良くありません。たとえば、pstack はコアダンプでは動作しません。
strace
システムコールトレーサ (Solaris OS の truss -t と同等)。
top
CPU 負荷が非常に高いプロセスを表示します。
vmstat
プロセス、メモリー、ページング、ブロック I/O、トラップ、および CPU アクティビティーに関する情報を報告します。

2.16.3 Windows オペレーティングシステム

次のツールは、Windows オペレーティングシステムで提供されます。さらに、MSDN ライブラリサイトにアクセスし、デバッグサポートを検索できます。

ツール
説明
dumpchk
メモリーダンプファイルが正しく作成されたことを確認するコマンド行ユーティリティー。このツールは、Microsoft Web サイトから入手可能な Debugging Tools for Windows ダウンロードに含まれています (「7.4.4 Windows でのクラッシュダンプの収集」を参照)。
msdev デバッガ
Visual C++ および Win32 デバッガの起動に使用可能なコマンド行ユーティリティー。
userdump
ユーザーモードプロセスダンプユーティリティー。このツールは、Microsoft Web サイトから入手可能な OEM Support Tools ダウンロードに含まれています (セクション「7.4.4 Windows でのクラッシュダンプの収集」を参照)。
windbg
Windows アプリケーションまたはクラッシュダンプのデバッグに使用可能な Windows デバッガ。このツールは、Microsoft Web サイトから入手可能な Debugging Tools for Windows ダウンロードに含まれています (セクション「7.4.4 Windows でのクラッシュダンプの収集」を参照)。
/Md および /Mdd コンパイラオプション
メモリー割り当てを追跡するための追加サポートを自動的に含めるコンパイラオプション。

2.16.4 Solaris 10 OS で導入されたツール

このセクションでは、バージョン 10 の Solaris オペレーティングシステムで導入された診断ツールのいくつかについて詳しく説明します。

2.16.4.1 pmap ツールの改善

pmap ユーティリティーは、Solaris 10 OS でスタックセグメントがテキスト [stack] 付きで出力されるように改善されました。このテキストはスタックの場所を見つけるのに役立ちます。

次の例は、このツールからの出力の一部を示しています。

19846:    /net/myserver/export1/user/j2sdk6/bin/java -Djava.endorsed.d
00010000      72K r-x--  /export/disk09/jdk/6/rc/b63/binaries/solsparc/bin/java
00030000      16K rwx--  /export/disk09/jdk/6/rc/b63/binaries/solsparc/bin/java
00034000   32544K rwx--    [ heap ]
D1378000      32K rwx-R    [ stack tid=44 ]
D1478000      32K rwx-R    [ stack tid=43 ]
D1578000      32K rwx-R    [ stack tid=42 ]
D1678000      32K rwx-R    [ stack tid=41 ]
D1778000      32K rwx-R    [ stack tid=40 ]
D1878000      32K rwx-R    [ stack tid=39 ]
D1974000      48K rwx-R    [ stack tid=38 ]
D1A78000      32K rwx-R    [ stack tid=37 ]
D1B78000      32K rwx-R    [ stack tid=36 ]
[.. more lines removed here to reduce output ..]
FF370000       8K r-x--  /usr/lib/libsched.so.1
FF380000       8K r-x--  /platform/sun4u-us3/lib/libc_psr.so.1
FF390000      16K r-x--  /lib/libthread.so.1
FF3A4000       8K rwx--  /lib/libthread.so.1
FF3B0000       8K r-x--  /lib/libdl.so.1
FF3C0000     168K r-x--  /lib/ld.so.1
FF3F8000       8K rwx--  /lib/ld.so.1
FF3FA000       8K rwx--  /lib/ld.so.1
FFB80000      24K -----    [ anon ]
FFBF0000      64K rwx--    [ stack ]
 total    167224K
2.16.4.2 pstack ツールの改善

Solaris 10 OS リリースより前の pstack ユーティリティーは、Java 言語をサポートしていませんでした。解釈済みおよび (HotSpot で) コンパイル済み Java メソッドの両方で、16 進アドレスを出力していました。

Solaris 10 OS 以降の pstack コマンド行ツールは、コアファイルまたはライブプロセスから混合モードのスタックトレース (Java および C/C++ フレーム) を出力します。このツールは、解釈済み、コンパイル済み、およびインライン化された Java メソッドに対し、Java メソッド名を出力します。

2.16.4.3 DTrace ツールの使用

Solaris 10 OS に含まれる DTrace ツールを使えば、オペレーティングシステムのカーネルおよびユーザーレベルのプログラムの動的トレースを行えます。このツールでは、システムコールの入口と出口、ユーザーモード関数の入口と出口、およびその他多くのプローブポイントでのスクリプトがサポートされます。スクリプトは、安全なポインタセマンティクスを備えた、C に似た言語である D プログラミング言語で記述されます。これらのスクリプトは、問題のトラブルシューティングやパフォーマンス問題の解決に役立つ可能性があります。

dtrace コマンドは、DTrace ツールに対する汎用のフロントエンドです。このコマンドには、D 言語を呼び出したり、バッファー内のトレースデータを取得したり、トレースデータを書式設定/出力するための一連の基本ルーチンにアクセスしたりするための、単純なインタフェースが用意されています。

カスタマイズされた独自の DTrace スクリプトを D 言語を使って記述したり、すでにさまざまなサイト上で入手可能な多くのスクリプトから 1 つ以上をダウンロードして使用したりすることもできます。

プローブは、プロバイダと呼ばれるカーネルモジュールによって提供および計測されます。プローブプロバイダによって提供されるタイプのトレースには、ユーザー命令トレース、関数境界トレース、カーネルロック計測、プロファイル割り込み、システムコールトレースなどがあります。独自のスクリプトを記述する場合は、D 言語を使ってプローブを有効にしてくださう。この言語では条件トレースや出力書式設定を行うこともできます。

dtrace -l オプションを使って、Solaris OS で使用可能な一連のプロバイダやプローブを調べることができます。

DTrace Toolkit は、OpenSolaris DTrace コミュニティーで開発されたドキュメント付きの有用なスクリプトを集めたものです。http://www.opensolaris.org/os/community/dtrace/dtracetoolkit/ を参照してください

DTrace の詳細情報が次の場所で提供されています。

Java HotSpot VM のプローブプロバイダ

JDK 7 以降では、Java HotSpot VM に組み込みプローブプロバイダが 2 つ含まれています。hotspothotspot_jni です。これらのプロバイダが提供するプローブを使えば、VM および実行中の Java アプリケーションの内部状態やアクティビティーをモニターできます。

hotspot プロバイダのプローブは次のように分類できます。

ネイティブコードから Java コードへの呼び出しの場合、ネイティブコードは JNI インタフェース経由で呼び出しを行う必要があります。hotspot_jni プロバイダは、Java コードを呼び出したり VM の状態を検査したりするために JNI インタフェースに用意されているメソッドごとに、入口と出口における DTrace プローブを管理します。

DTrace の使用例

プローブポイントで現在のスレッドのスタックトレースを出力するには、ustack 組み込み関数を使用します。この関数は、C/C++ ネイティブ関数の名前だけでなく、Java メソッドの名前も出力します。次は、あるスレッドが read システムコールを呼び出したときに完全なスタックトレースを出力する単純な D スクリプトです。

#!/usr/sbin/dtrace -s
syscall::read:entry 
/pid == $1 && tid == 1/ {    
   ustack(50, 0x2000);
}

上のスクリプトは read.d という名前のファイルに格納され、次のコマンドで実行されます。

read.d pid-of-the-Java-process-that-is-traced

Java アプリケーションで多数の I/O が生成されたり、なんらかの予期しない遅延が発生したりした場合、DTrace ツールやその ustack() アクションを使用すれば、問題を診断しやすくなる可能性があります。

2.17 診断ツールの開発

JDK ソフトウェアに含まれる広範なアプリケーションプログラミングインタフェース (API) を使えば、Java 実行環境に配備されたアプリケーションの問題を監視、モニター、プロファイル、デバッグ、および診断するためのツールを開発できます。新しいツールの開発はこのドキュメントの対象外です。代わりにこのセクションでは、使用可能なプログラミングインタフェースの概要を簡単に説明します。JDK ダウンロードに含まれるコード例やデモコードも参照してください。

2.17.1 java.lang.management パッケージ

java.lang.management パッケージは、Java 仮想マシンやオペレーティングシステムをモニターおよび管理するための管理インタフェースを提供します。具体的には、次の各システムのインタフェースがカバーされています。

java.lang.management パッケージは、Java SE API ドキュメントで詳しく説明されています。

JDK リリースには、java.lang.management パッケージの使用方法を示すコード例が含まれています。これらの例は $JAVA_HOME/demo/management ディレクトリで見つけることができます。これらの例のいくつかを次に示します。

JDK リリースには java.lang.management パッケージのほかに、プラットフォーム拡張が com.sun.management パッケージとして含まれています。プラットフォーム拡張には、コレクションをサイクルで実行するガベージコレクタから詳細統計を取得するための管理インタフェースが含まれています。これらの拡張には、オペレーティングシステムから追加のメモリー統計を取得するための管理インタフェースも含まれています。

プラットフォーム拡張の詳細については、Java SE API ドキュメント: Java プラットフォーム用の監視および管理インタフェースで見つけることができます。

2.17.2 java.lang.instrument パッケージ

java.lang.instrument パッケージは、Java プログラミング言語エージェントが Java VM で実行中のプログラムを計測することを許可するサービスを提供します。インストゥルメンテーションは、プロファイラなどのツールや、メソッド呼び出しをトレースするためのツールなどで使用されます。このパッケージを使えば、ロード時および動的計測の両方が容易になります。また、ロード済みクラスに関する情報や特定のオブジェクトが消費するストレージ量に関する情報を取得するメソッドも含まれています。

java.lang.instrument パッケージは、Java SE API ドキュメントで詳しく説明されています。

2.17.3 java.lang.Thread クラス

java.lang.Thread クラスには、すべてのライブスレッドのスタックトレースのマップを返す、getAllStackTraces という名前の静的メソッドが含まれています。Thread クラスにはさらに、スレッドの状態を返す getState という名前のメソッドも含まれています。状態は java.lang.Thread.State 列挙で定義されます。これらのメソッドは、診断またはモニタリング機能をアプリケーションに追加する際に役立つ可能性があります。これらのメソッドは、API ドキュメントで詳しく説明されています。

2.17.4 Java Virtual Machine Tools Interface

Java Virtual Machine Tools Interface (JVM TI) は、広範な開発/モニタリングツールの開発に使用可能な、ネイティブ (C/C++) プログラミングインタフェースです。JVM TI は、VM の状態にアクセスする必要のある各種ツール (プロファイリングツール、デバッグツール、モニタリングツール、スレッド分析ツール、カバレージ分析ツールを含むがこれに限らない) のためのインタフェースを提供します。

JVM TI に依存するエージェントのいくつかの例を次に示します。

JVM TI の仕様は、JVM Tool Interface のドキュメントで見つけることができます。

JDK リリースには、JVM TI の使用方法を示すコード例が含まれています。これらの例は $JAVA_HOME/demo/jvmti ディレクトリで見つけることができます。いくつかの例を次に示します。

2.17.5 Java Platform Debugger Architecture

Java Platform Debugger Architecture (JPDA) は、デバッガやデバッガに似たツールが使用するために設計されたアーキテクチャーです。これは、2 つのプログラミングインタフェースと 1 つのワイヤープロトコルから構成されています。

JPDA の完全な説明 (仕様を含む) は、Java Platform Debugger Architecture (JPDA) のドキュメントにあります。

JPDA 構造のグラフィック表示は、Java Platform Debugger Architecture の説明で示されています。

jdb ユーティリティーは、コマンド行デバッガの例として JDK リリースに含まれています。jdb ユーティリティーは、Java Debug Interface (JDI) を使ってターゲット VM を起動または接続します。「2.4 jdb ユーティリティー」を参照してください。

JDI を使えば、従来のデバッガタイプのツールだけでなく、ポストモーテム診断の際や、ツールが非協力的なプロセス (ハングアッププロセスなど) に接続する必要があるシナリオで役に立つツールを開発することもできます。JDI ベースのツールをクラッシュダンプやハングアッププロセスに接続するために使用可能な JDI コネクタについては、「2.4 jdb ユーティリティー」を参照してください。