プライマリ・コンテンツに移動
Java Platform, Standard Editionトラブルシューティング・ガイド
リリース10
E94990-01
目次へ移動
目次

前
次

2 診断ツール

この章では、Java Development Kit (JDK)で使用可能な診断および他のモニタリング・ツールを紹介します。その後で、JDK 9の診断ツールおよび各種オペレーティング・システム固有のトラブルシューティング・ツールについて詳しく説明します。この章の最後では、JDKが提供するアプリケーション・プログラミング・インタフェース(API)を使用してカスタム診断ツールを開発する方法について説明します。

この章の構成は、次のとおりです。

診断ツールの概要

この項で説明するコマンド行ユーティリティのほとんどは、JDKに含まれているか、オペレーティング・システムのネイティブなツールやユーティリティです。

JDKコマンド行ユーティリティはJDKのダウンロードに含まれていますが、Java Runtime Environment (JRE)にデプロイされたアプリケーションの問題の診断やモニターのためにそれらを使用できるかどうかを検討するのは重要なことです。

一般に、診断ツールやオプションは、様々なメカニズムを使用して報告対象の情報を取得します。それらのメカニズムは仮想マシン(VM)実装、オペレーティング・システムおよびリリースに固有のものです。通常、ツールの一部のみが、特定の時点で特定の問題に適用可能です。「-XX」という接頭辞が付いたコマンド行オプションは、Java HotSpot VMに固有のものです。「Java HotSpot VMコマンド行オプション」を参照してください。

注意:

-XXオプションはJava APIの一部ではなく、リリースごとに変わる可能性があります。

これらのツールおよびオプションは、トラブルシューティングの対象となっている問題のタイプに応じて、いくつかのカテゴリに分けられます。場合によっては、1つ以上のカテゴリに分けられるツールやオプションもあります。

注意:

この項で説明するコマンド行ユーティリティのいくつかは、試験的なものです。jstackjinfo、およびjmapユーティリティが、試験的なユーティリティの例です。以前のjstackjinfoおよびjmapユーティリティのかわりに最新の診断ツールjcmdの使用をお薦めします。

Java Mission Control

Java Mission Control (JMC)は、HotSpot JVM用の新しいJDKプロファイリングおよび診断ツール・プラットフォームです。

基本的なモニタリングと管理、および本番稼働時のプロファイリングと診断を行う高性能なツール・スイートです。Java Mission Controlは、プロファイリング・ツールにつきもののパフォーマンス・オーバーヘッドの問題を最小限に抑えます。このツールはJVMに組み込まれた商用機能であり、実行時に使用できます。

Java Flight Recorder (JFR)は商用機能です。開発者のデスクトップおよびラップトップ上では無償で、また評価目的であればテスト環境、開発環境および本番環境で使用できます。ただし、JFRを本番サーバーで有効にする場合は、商用ライセンスが必要です。それ以外の目的でJMC UIをJDK上で使用する場合、商用ライセンスは必要ありません

Java Mission Control (JMC)は、Java管理コンソール(JMX)とJava Flight Recorder (JFR)の他、ツールからダウンロード可能ないくつかのプラグインで構成されます。JMXはJavaアプリケーションのモニタリングおよび管理用ツールで、JFRはプロファイリング・ツールです。Java Mission Controlは、Eclipse IDE用のプラグインのセットとしても使用可能です。

次のトピックでは、Java Mission Controlでトラブルシューティングを行う方法を説明します。

Java Mission Controlによるトラブルシューティング

Java Mission Controlで実行可能なトラブルシューティング・アクティビティ。

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

  • Java管理コンソール(JMX)が実行中のJVMに接続し、主な特性をリアルタイムに収集して表示します。
  • JVMのユーザー指定のカスタム・アクションとルールのトリガーを設定します。
  • 試験的プラグイン(WLSDTraceJOverflowおよび他のJMCツールのプラグイン)でトラブルシューティング・アクティビティを実行します。
    • DTraceプラグインはDScript言語を拡張したもので、自己記述型のイベントを生成します。Javaフライト・レコーダのように可視化できます。
    • JOverflowはヒープの未使用領域(空/疎コレクション)を分析するためのもう1つのプラグイン・ツールです。JOverflowプラグインの使用を最適化するには、JDK 8以降のリリースの使用をお薦めします。
  • Java Mission ControlのJavaフライト記録(JFR)はイベントの分析に使用できます。事前構成済のタブを使用すると、コード、メモリーとGC、スレッドとI/Oといったよく使用される様々な領域で簡単にドリルダウンできます。一般イベント・タブと操作イベント・タブを組み合せて使用することで、特定のプロパティのイベント・セットを詳細にドリルダウンし、手早く焦点を絞ることができます。通常、「イベント」タブにはチェック・ボックスがあり、「操作セット」内のイベントのみが表示されます。
    • JFRをJMCクライアント用のプラグインとして使用すると、論理的にグループ化された表、グラフおよびダイアルに診断情報が表示されます。これを使用すると、問題に焦点を当てるために必要となる期間および詳細レベルを選択できます。「Javaフライト・レコーダ」を参照してください。
  • Java Mission Controlプラグインは、Java Management Extensions (JMX)エージェントを使用してJVMに接続します。JMXは、アプリケーション、デバイス、サービス、Java仮想マシンなどのリソースを管理およびモニタリングするための標準APIです。

    JMCの詳細は、JMCのドキュメントを参照してください。

Javaフライト記録とは

Java Flight Recorder (JFR)は商用機能です。開発者のデスクトップおよびラップトップ上では無償で、また評価目的であればテスト環境、開発環境および本番環境で使用できます。

ただし、JFRを本番サーバーで有効にする場合は、商用ライセンスが必要です。それ以外の目的でJMC UIをJDK上で使用する場合、商用ライセンスは必要ありません

JFRの商用機能と入手方法の詳細は、製品マニュアルを参照してください。

JFRの商用ライセンスの詳細は、ライセンス契約を参照してください。

Javaフライト・レコーダは、JavaランタイムおよびJavaランタイムで実行されているJavaアプリケーションの詳細情報を記録します。記録プロセスによるオーバーヘッドはほとんど発生しません。データは、イベントと呼ばれるタイム・スタンプ付きのデータ・ポイントとして記録されます。一般的なイベントには、ロックを待機中のスレッド、ガベージ・コレクション、定期的なCPU使用率データなどがあります。

フライト記録を作成する場合は、保存するイベントを選択します。これは記録テンプレートと呼ばれています。一部のテンプレートは、ごく基本的なイベントのみを保存し、パフォーマンスにほとんど影響を与えません。他のテンプレートは、いくらかのパフォーマンス・オーバーヘッドが発生し、追加情報を得るためにGCをトリガーする場合もあります。通常、オーバーヘッドが数パーセントを超えることはほとんどありません。

フライト記録は、パフォーマンスの問題からメモリー・リーク、重いロック競合まで、広範囲の問題のデバッグに使用できます。

次のトピックでは、Javaフライト記録を作成する記録の種類について説明します。

記録の種類

連続記録とプロファイリング記録の2種類のフライト記録があります。

  • 連続記録: 連続記録は、常時オンの記録で、たとえば、最近6時間のデータを保存します。アプリケーションで問題が発生した場合は、たとえば、最後の1時間のデータをダンプし、問題発生時に何が起こったかを調べることができます。

    連続記録のデフォルト設定は、低いオーバーヘッドで記録プロファイルを使用することです。このプロファイルは、ヒープの統計や割当てプロファイリングを取得しませんが、役立つデータを大量に収集します。

    連続記録は、常に実行されていることが重要であり、あまり発生しない問題をデバッグする際に便利です。記録は、jcmdまたはJMCのいずれかを使用して手動でダンプできます。また、特定の条件が満たされたときにフライト記録をダンプするためにJMCにトリガーを設定することもできます。

  • プロファイリング記録: プロファイリング記録は、オンになると、一定時間実行した後、停止する記録です。通常、プロファイリング記録では、より多くのイベントが有効であり、パフォーマンスへの影響がいくらか大きくなる場合があります。オンにするイベントは、プロファイリング記録の使用に応じて変更できます。

    プロファイリング記録の一般的なユース・ケースは次のとおりです。

    • 最もよく実行されるメソッドおよび最も多くのオブジェクトが作成される場所のプロファイルを記録する。

    • メモリー・リーク発生の指標となる、ヒープ使用量の増加を示しているクラスを探す。

    • 同期に起因するボトルネックおよび多数のこのようなユース・ケースを探す。

    プロファイリング記録は、特定の問題のトラブルシューティングをしていない場合にも、多くの情報を提供します。プロファイリング記録では、アプリケーションの全体像を見て、ボトルネックまたは改善の必要な領域を見つけることができます。

注意:

通常のオーバーヘッドは2%程度であるので、パフォーマンスまたはレイテンシに対して非常に慎重である場合を除き、プロファイリング記録は本番環境で実行できます(これはJFRの主要ユース・ケースの1つです)。

フライト記録の作成方法

次の項では、フライト記録を作成する3つの方法について説明します。

Java Mission Controlによるフライト記録の作成

フライト記録を簡単に管理するには、Java Mission Control (JMC)を使用します。

前提条件:

開始するには、図2-1に示すように左端のフレームのJVMブラウザで自分のサーバーを見つけます。

図2-1 Java Mission Control - サーバーを見つける

図2-1の説明が続きます
「図2-1 Java Mission Control - サーバーを見つける」の説明

デフォルトでは、ローカルで実行中のすべてのJVM一覧が表示されます。リモートJVM (JMCを実行しているユーザーと同じ有効ユーザーで実行)はリモートJMXエージェントを使用するように設定する必要があります。次に、新しいJVM接続ボタンをクリックし、ネットワークの詳細を入力します。

JDK 8u40より前のリリースでは、-XX:+UnlockCommercialFeatures -XX:FlightRecorderフラグを指定してJVMが起動されている必要がありました。

JDK 8u40リリースからは、Javaフライト・レコーダを実行時に有効にすることができます。

Java Mission Controlを使用してフライト記録を作成する3つの方法は次のとおりです。

  1. 実行中の記録の確認: JVMブラウザのノードを展開して実行中の記録を表示します。図2-2は、実行中の連続記録(無限大記号を持つ)と一定時間のプロファイリング記録を示しています。

    図2-2 Java Mission Control - 実行中の記録

    図2-2の説明が続きます
    「図2-2 Java Mission Control - 実行中の記録」の説明

    任意の記録を右クリックして、記録をダンプ、編集または停止します。プロファイリング記録を停止しても記録ファイルは作成され、プロファイリング記録を閉じると記録が破棄されます。

  2. 連続記録のダンプ: JVMブラウザで連続記録を右クリックし、ファイルへのダンプを選択します。図2-3に示すように、表示されるダイアログ・ボックスで、使用可能なすべてのデータまたは記録の最後の部分のみをダンプすることを選択します。

    図2-3 Java Mission Control - 連続記録のダンプ

    図2-3の説明が続きます
    「図2-3 Java Mission Control - 連続記録のダンプ」の説明
  3. 新しい記録の開始: 新しい記録を開始するには、記録するJVMを右クリックし、「フライト記録の開始」を選択します。図2-4に示すようなウィンドウが表示されます。

    図2-4 Java Mission Control - フライト記録の開始

    図2-4の説明が続きます
    「図2-4 Java Mission Control - フライト記録の開始」の説明

    図2-4に示すように、「一定時間の記録」(プロファイリング記録)または「連続記録」のいずれかを選択します。連続記録の場合は、保存するイベントの最大サイズまたは最大保持時間も指定します。

    「イベント設定」を選択することもできます。独自のテンプレートを作成することもできますが、すべてのユース・ケースの99%では、連続テンプレート(記録オーバーヘッドが非常に低い )またはプロファイリング・テンプレート(より多くのデータと若干のオーバヘッド)のいずれかを選択できます。注意: プロファイリング記録の通常のオーバーヘッドは2%程度です。

    完了後、「次へ」をクリックします。図2-5に示すように、次の画面では、様々なユース・ケースに合わせてテンプレートに修正を加えることができます。

    図2-5 Java Mission Control - プロファイリングのイベント・オプション

    図2-5の説明が続きます
    「図2-5 Java Mission Control - プロファイリングのイベント・オプション」の説明

    デフォルトの設定では、データとパフォーマンスのバランスが良くとれています。いくつかのケースでは、別のイベントを追加する場合があります。たとえば、メモリー・リークを調査し、多くのJavaヒープを消費するオブジェクトを見つける場合は、ヒープ統計を有効にします。これにより、記録の開始時と終了時に2つのOldコレクションがトリガーされるので、待機時間が増えます。また、キャッチされた例外も含め、スローされたすべての例外を表示することも選択できます。一部のアプリケーションでは、多くのイベントが生成されます。

    しきい値は、記録イベントの長さです。たとえば、デフォルトでは、10msを超える同期イベントが収集されます。これは、スレッドが10msを超えてロックを待機している場合、イベントが保存されることを意味します。短い競合の詳細データを取得するには、この値を下げることができます。

    「スレッド・ダンプ」の設定は、定期的なスレッド・ダンプを実行するためのオプションを提供します。これらは、診断コマンドThread.printの使用、またはjstackツールの使用により取得されるような、通常のテキストのスレッド・ダンプです。スレッド・ダンプは、イベントを補完します。

コマンド行での起動フラグによるフライト記録の作成

コマンド行で起動フラグを使用して、プロファイリング記録の作成、連続記録、診断コマンドの使用を行います。

JFRフラグの詳細な説明は、Java Platform, Standard Editionツール・リファレンスの高度なランタイム・オプションに関する項を参照してください。

コマンド行で起動フラグを使用してフライト記録を作成する3つの方法は次のとおりです。

  1. プロファイリング記録の開始: -XX:StartFlightRecordingオプションを使用して、アプリケーションの起動時に一定時間の記録を設定できます。JFRは商用の機能なので、-XX:+UnlockCommercialFeaturesオプションを指定する必要があります。次の例は、MyAppアプリケーションを実行し、JVMを起動してから20秒後に60秒間の記録を開始し、それをmyrecording.jfrという名前のファイルに保存する方法を示しています。

    java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:StartFlightRecording=delay=20s,duration=60s,name=myrecording,filename=C:\TEMP\myrecording.jfr,settings=profile MyApp

    settingsパラメータにはテンプレートへのパスまたはテンプレート名を指定します。デフォルトのテンプレートはjre/lib/jfrフォルダにあります。2つの標準プロファイルがあります: デフォルトは、主に連続記録のために作成されたオーバーヘッドの低い設定で、プロファイルは、より多くのデータを収集し、主にプロファイリング記録用です。

  2. 連続記録の開始: -XX:FlightRecorderOptionsを使用して、コマンド行から連続記録を開始することもできます。これらのフラグは、必要に応じて後でダンプできる連続記録を開始します。次の例は、連続記録を示しています。一時データはディスクに保存され(/tmpフォルダ)、6時間のデータが保存されます。

    java -XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=defaultrecording=true,disk=true,repository=/tmp,maxage=6h,settings=default MyApp

    注意:

    実際に記録をダンプするときは、ダンプ・ファイルのための新しい場所を指定するので、リポジトリ内のファイルは一時的です。

    Javaフライト記録の構成および管理の詳細は、Java Flight Recorderランタイム・ガイドを参照してください。

  3. 診断コマンドの使用:

    Javaコマンド行の診断コマンドを使用して記録を制御することもできます。診断コマンドを実行するもっとも単純な方法は、Javaインストール・ディレクトリにある jcmdツールを使用することです。詳細は、「jcmdユーティリティ」を参照してください。

トリガーによる自動記録

条件が満たされた場合にフライト記録を自動的に開始またはダンプするようにJava Mission Controlを設定できます。これはJMXコンソールから実行します。JMXコンソールを起動するには、JVMブラウザでアプリケーションを見つけてそれを右クリックし、JMXブラウザの起動を選択します。

図2-6に示すように、画面の下部にある「トリガー」タブを選択します。

図2-6 Java Mission Control - 自動記録

図2-6の説明が続きます
「図2-6 Java Mission Control - 自動記録」の説明

アプリケーション内の任意のMBeanにトリガーを作成することがきます。高いCPU使用率、デッドロック・スレッド、過剰なライブ・セットなどのいくかの一般的な条件のためのデフォルト・トリガーが設定されています。「追加」を選択して、アプリケーション内の任意のMBean(アプリケーションに固有のものを含む)を選択します。トリガーを選択するとき、満たす必要のある条件も選択できます。詳細は、右上の疑問符をクリックして組込みのヘルプを参照してください。

複数のトリガーを実行するには、トリガーの横のボックスをクリックします。

条件を選択したら、「アクション」タブをクリックします。次に、条件が満たされたときに実行する処理を選択します。最後に、図2-7に示すように、連続記録のダンプまたは期間限定のフライト記録の開始のいずれかを選択します。

図2-7 Java Mission Control - トリガーの使用



フライト記録の検査

フライト記録を検査するためのサンプルJFRの取得方法、およびフライト記録を分析するためのJava Mission Controlの様々なタブについての説明。

次の項で説明します。

検査のためのサンプルJFRの取得方法

フライト記録を作成して、Mission Controlでそれを開くことができます。

フライト記録を作成した後、Mission Controlでそれを開くことができます。フライト記録を検査するための簡単な方法:

  • Mission Controlを開き、「JVMブラウザ」タブを選択する。
  • Mission Controlを実行しているJVMオプションを選択して短い記録を作成する。

    フライト記録を開くと、「全般」、「メモリー」、「コード」、「スレッド」、「I/O」、「システム」および「イベント」などのいくつかのメイン・タブが表示されます。プラグインがインストールされている場合は、他のメイン・タブも表示されることがあります。これらのメイン・タブには、それぞれのサブタブがあります。疑問符をクリックして組込みのヘルプのメイン・タブおよびサブタブに関する項を参照してください。

範囲ナビゲータ

範囲ナビゲータを使用して、フライト記録を検査します。

各タブの上部のビューに、範囲ナビゲータがあります。

図2-8 フライト記録の検査 - 範囲ナビゲータ



図2-8の縦棒は、記録内のイベントを表します。棒の高さが高いほど、より多くのイベントがその時点で発生しています。選択された時間の端をドラッグして、記録のズーム・インまたはズーム・アウトができます。範囲ナビゲータをダブルクリックすると、ズーム・アウトして記録全体が表示されます。すべてのサブタブに同じズーム・レベルを適用するには、「選択の同期」チェック・ボックスをクリックします。

詳細は、組込みヘルプの範囲ナビゲータの使用に関する項を参照してください。イベントの名前は、タブの名前どおりです。

「全般」タブ

「全般」タブのフライト記録を検査します。

「全般」タブには、アプリケーション全般について説明するいくつかのサブタブが含まれています。図2-9に示すように、最初のサブタブは「概要」で、ここには最大ヒープ使用量、合計CPU使用率およびGC一時休止時間などの基本情報が表示されます。

図2-9 フライト記録の検査 - 「全般」タブ

図2-9の説明が続きます
「図2-9 フライト記録の検査 - 「全般」タブ」の説明

また、CPU使用率の経時的推移、アプリケーションでの使用状況とマシンでの合計を調べます。このタブは、アプリケーションで直接に問題が発生したときに調べるための便利なタブです。たとえば、100%近くまで急上昇しているCPU使用率、低すぎるCPU使用率、またはガベージ・コレクションの一時休止などに注意してください。

注意: ヒープ統計を指定して開始されたプロファイリング記録は、記録の開始時と終了時に、他のコレクションよりも長くかかる可能性がある、2つのOldコレクションを取得します。

また、「JVM情報」サブタブには、JVM情報が表示されます。起動パラメータのサブタブの「システム・プロパティ」には、設定されたすべてのシステム・プロパティが表示され、「記録」には、オンにされたイベントなど、特定の記録に関する情報が表示されます。すべてのタブおよびサブタブについて組込みの詳細を参照するには、疑問符をクリックしてください。

「メモリー」タブ

「メモリー」タブのフライト記録を検査します。

「メモリー」タブには、ガベージ・コレクション、割当てパターンおよびオブジェクト統計に関する情報が含まれています。このタブは、メモリー・リークのデバッグおよびGCのチューニングのために特に役立ちます。

「概要」タブには、メモリー使用量に関する一般情報およびガベージ・コレクションに関する統計情報が表示されます。注意: 「概要」タブのグラフでは、目盛の最大値がマシンで使用可能な物理メモリーです。そのため、Javaヒープは、下部のわずかな部分のみを取る場合があります。

「メモリー」タブの3つのサブタブは次のとおりです。

  • 「ガベージ・コレクション」タブ: 「ガベージ・コレクション」タブには、メモリー使用量の経時的推移およびすべてのガベージ・コレクションに関する情報が表示されます。

    図2-10 フライト記録の検査 - ガベージ・コレクション

    図2-10の説明が続きます
    「図2-10 フライト記録の検査 - ガベージ・コレクション」の説明

    図2-10に示すように、ヒープ使用量のスパイク状のパターンはまったく正常です。ほとんどのアプリケーションでは、一時オブジェクトが絶えず割り当てられています。条件が満たされると、ガベージ・コレクション(GC)がトリガーされ、使用されなくなったすべてのオブジェクトが削除されます。したがって、ヒープ使用量は、GCがトリガーされるまで絶え間なく増加した後、急激に減少します。

    JavaのほとんどのGCには、何らかの小規模なガベージ・コレクションがあります。Old GCではJavaヒープ全体が対象となり、他のGCではヒープの一部を調べる場合があります。Oldコレクション後のヒープ使用量は、アプリケーションで使用されているメモリーであり、ライブ・セットと呼ばれています。

    ヒープ統計を有効にして生成されるフライト記録は、Old GCで開始および終了します。GCの一覧からそのOld GCを選択し、「全般」タブを選択して「GC理由」を参照すると、ヒープ検査によるGCの開始であることがわかります。通常、これらのGCは、他のGCよりも少し時間がかかります。

    メモリー・リークに対処するための最適な方法としては、最初と最後のOld GCでの「GC後のヒープ」の値を確認してください。この値が経時的に増加している場合は、メモリー・リークの可能性があります。

    「GC回数」タブには、GCの実行にかかった時間とGCのためにアプリケーションが完全に一時休止する時間に関する情報があります。「GC構成」タブには、GCの構成に関する情報があります。これらのタブの詳細は、右上の疑問符をクリックして組込みのヘルプを参照してください。

  • 「割当て」タブ: 図2-11では、行われたすべてのメモリー割当ての選択を示しています。Javaの小さなオブジェクトは、TLAB (Thread Local Area Buffer)に割り当てられます。TLABは、新しいオブジェクトが割り当てられている小さなメモリー領域です。TLABが一杯になると、スレッドが新しいものを取得します。すべてのメモリー割当てをログすると、オーバーヘッドが生じるので、新しいTLABをトリガーしたすべての割当てがログされます。大きいオブジェクトは、TLAB外に割り当てられ、これらもログされます。

    図2-11 フライト記録の検査 - 「割当て」タブ

    図2-11の説明が続きます
    「図2-11 フライト記録の検査 - 「割当て」タブ」の説明

    各クラスのメモリー割当てを推定するには、「新しいTLABの割当て」タブ、「割当て」タブの順に選択します。これらの割当ては、新しいTLABをトリガーするために起こるオブジェクトの割当てです。char型の配列は、新しいTLABを最も多くトリガーします。どれだけのメモリーがchar型の配列として割り当てられているかは不明です。TLABのサイズは、char型の配列によって割り当てられるメモリーを推定するのに役立ちます。

    図2-11は、最も多くのメモリーを割り当てるchar型の配列の例です。いずれかのクラスをクリックして、これらの割当てのスタック・トレースを参照してください。記録の例では、すべての割当てプレッシャの44%がchar型の配列に由来し、27%がStringBuilder.toStringから呼び出されるArray.copyOfRangeに由来することを示しています。通常、StringBuilder.toStringは、Throwable.printStackTraceおよびStackTraceElement.toStringによって呼び出されます。これらのメソッドの呼出しを確認するには、さらに展開します。

    注意: アプリケーションによる一時オブジェクトの割当てが多いほど、アプリケーションで必要なガベージ・コレクションが増えます。「割当て」タブは、ほとんどの割当てを見つけてアプリケーションのGCプレッジャを減らすことに役立ちます。「TLAB外の割当て」タブでは、通常、「新しいTLABの割当て」タブよりもメモリー・プレッシャが少ない、大きいメモリー割当てを参照できます。

  • 「オブジェクト統計」タブ: 「オブジェクト統計」タブには、ほとんどのライブ・セットを持つクラスが表示されます。ライブ・セットについて理解するには、「「メモリー」タブ」「ガベージ・コレクション」サブタブを参照してください。図2-12では、フライト記録のヒープ統計を示しています。データを表示するには、フライト記録のヒープ統計を有効にしてください。下部の「上位の増加」タブでは、フライト記録中に各オブジェクト・タイプのサイズがどれだけ増加したかを示しています。特定のオブジェクト・タイプのサイズが大きく増加した場合にはメモリー・リークを示していますが、わずかな変動は正常です。特に、標準Javaクラス以外の上位の増加を調査します。

    図2-12 フライト記録の検査 - 「オブジェクト統計」タブ

    図2-12の説明が続きます
    「図2-12 フライト記録の検査 - 「オブジェクト統計」タブ」の説明

「コード」タブ

「コード」タブのフライト記録を検査します。

「コード」タブには、アプリケーションが時間の大半を費やしている場所の情報が含まれます。「概要」サブタブには、最も多くの実行時間を費やしたパッケージおよびクラスが表示されます。これはサンプリングからのデータです。JFRでは、一定の間隔で実行中のスレッドのサンプルを取ります。実際のコードを実行しているスレッドのみがサンプリングされ、スリープ中、ロックまたはI/Oを待機中のスレッドは表示されません。

実際のコードを実行するためのアプリケーション時間の詳細は、「ホット・メソッド」サブタブを参照してください。

図2-13 フライト記録の検査 - 「コード」タブ

図2-13の説明が続きます
「図2-13 フライト記録の検査 - 「コード」タブ」の説明

図2-13では、最も多くサンプリングされたメソッドを示しています。これらの呼出し元を確認するには、サンプルを展開します。HashMap.getEntryの呼出しが多い場合は、最も多く呼び出したメソッドが見つかるまでこのノードを展開します。このタブは、アプリケーションのボトルネックを見つけるのに最適です。

「呼出しツリー」サブタブでは、同じイベントが下から(Thread.runなどから)順に表示されます。

「例外」サブタブには、スローされた例外が表示されます。デフォルトではエラーのみがログされますが、すべての例外を含めるには、新しい記録を開始するときにこの設定を変更します。

「コンパイル」サブタブには、アプリケーションが実行されていたときにコンパイルされたメソッドが表示されます。

「クラスのロード」サブタブには、時間の経過とともにロードされたクラス数、実際にロードされたクラスおよびアンロードされたクラスが表示されます。このサブタブは、記録の開始時にクラス・ロード・イベントが有効であった場合にのみ情報が表示されます。

これらのタブの詳細は、右上の疑問符をクリックして組込みのヘルプを参照してください。

「スレッド」タブ

「スレッド」タブのフライト記録を検査します。

「スレッド」タブには、スレッド、ロックの競合およびその他の待機時間に関する情報が含まれます。

「概要」サブタブには、CPU使用率およびスレッド数の経時的な推移が示されます。

「ホット・スレッド」サブタブには、ほとんどのコード実行を行うスレッドが表示されます。この情報は、「コード」タブの「ホット・メソッド」サブタブと同じサンプリング・データに基づいています。

「競合」タブは、ロックの競合に起因するボトルネックを見つけるのに役立ちます。

図2-14 フライト記録の検査 - 「競合」タブ

図2-14の説明が続きます
「図2-14 フライト記録の検査 - 「競合」タブ」の説明
図2-14では、同期のための待機時間が長いオブジェクトを示しています。各オブジェクトの待機時間のスタック・トレースを参照するには、クラスを選択します。通常、これらの一時休止は、別のスレッドがロックを保持している同期メソッドによって生じます。

注意:

デフォルトでは、10msより長い同期イベントのみが記録されますが、記録の開始時にこのしきい値を下げることができます。

「待機時間」サブタブは、たとえば、スリープまたは待機の呼出し、ソケットからの読取り、ファイルI/Oの待機など、その他の待機時間の原因を示します。

「スレッド・ダンプ」サブタブには、記録内でトリガーできる定期的なスレッド・ダンプが表示されます。

「ロック・インスタンス」サブタブには、同期のために最も待機しているオブジェクトの正確なインスタンスが表示されます。

これらのタブの詳細は、右上の疑問符をクリックして組込みのヘルプを参照してください。

「I/O」タブ

「I/O」タブには、ファイルの読取り、ファイルの書込み、ソケットの読取りおよびソケットの書込みに関する情報が表示されます。

このタブは、特に、I/O操作に時間がかかる場合など、アプリケーションに応じて役立ちます。

注意:

デフォルトでは、10msより長いイベントのみが表示されます。しきい値は、新しい記録を作成するときに変更できます。

「システム」タブ

「システム」タブは、アプリケーションが実行されているマシンのCPU、メモリーおよびOSに関する詳細を提供します。

また、環境変数およびJVMと同時に実行されている他のプロセスも表示されます。

「イベント」タブ

「イベント」タブには、記録のすべてのイベントが表示されます。

これは様々な方法で使用できる詳細タブです。これらのタブの詳細は、右上の疑問符をクリックして組込みのヘルプを参照してください。

jcmdユーティリティ

jcmdユーティリティを使用してJVMに診断コマンド・リクエストを送信し、JVMではこれらのリクエストを使用してJavaフライト記録の制御、トラブルシューティング、JVMおよびJavaアプリケーションの診断を行います。

jcmdはJVMが実行されているものと同じマシン上で使用され、JVMの起動で使用されたものと同じ有効なユーザーおよびグループ識別子を持っている必要があります。

特殊コマンドjcmd <process id/main class> PerfCounter.printは、プロセス内のすべてのパフォーマンス・カウンタを出力します。

コマンドjcmd <process id/main class> <command> [options]は、JVMにコマンドを送信します。

次の例に、jcmdユーティリティによるJVMへの診断コマンド・リクエストを示します。

> jcmd
5485 sun.tools.jcmd.JCmd
2125 MyProgram
 
> jcmd MyProgram help (or "jcmd 2125 help")
2125:
The following commands are available:
JFR.configure
JFR.stop
JFR.start
JFR.dump
JFR.check
VM.log
VM.native_memory
VM.check_commercial_features
VM.unlock_commercial_features
ManagementAgent.status
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
Compiler.directives_clear
Compiler.directives_remove
Compiler.directives_add
Compiler.directives_print
VM.print_touched_methods
Compiler.codecache
Compiler.codelist
Compiler.queue
VM.classloader_stats
Thread.print
JVMTI.data_dump
JVMTI.agent_load
VM.stringtable
VM.symboltable
VM.class_hierarchy
GC.class_stats
GC.class_histogram
GC.heap_dump
GC.finalizer_info
GC.heap_info
GC.run_finalization
GC.run
VM.info
VM.uptime
VM.dynlibs
VM.set_flag
VM.flags
VM.system_properties
VM.command_line
VM.version
help
For more information about a specific command use 'help <command>'. 

> jcmd MyProgram help Thread.print
2125:
Thread.print
Print all threads with stacktraces.
 
Impact: Medium: Depends on the number of threads.
 
Permission: java.lang.management.ManagementPermission(monitor)
 
Syntax : Thread.print [options]
 
Options: (options must be specified using the <key> or <key>=<value> syntax)
        -l : [optional] print java.util.concurrent locks (BOOLEAN, false)
 
> jcmd MyProgram Thread.print
2125:
2014-07-04 15:58:56
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.0-b69 mixed mode):
...

次の項では、jcmdユーティリティでの便利なコマンドおよびトラブルシューティング手法について説明します。

jcmdユーティリティの有用なコマンド

使用可能な診断コマンドはHotSpot VMのバージョンごとに異なる場合があるので、jcmd <process id/main class> helpを使用して、使用可能なすべてのオプションを確認することをお薦めします。

jcmdツールに含まれている非常に役立つコマンドの一部を次に示します。jcmd <process id/main class> help <command>を使用すれば、該当するコマンドのその他のオプションをいつでも確認できることを覚えておいてください。

  • HotSpotおよびJDKのバージョンIDの出力
    jcmd <process id/main class> VM.version
  • VMに設定されているすべてのシステム・プロパティの出力

    数百行の情報が表示される可能性があります。

    jcmd <process id/main class> VM.system_properties

  • VMで使用されるすべてのフラグの出力

    フラグを指定していない場合でも、いくつかのデフォルト値(初期ヒープ・サイズや最大ヒープ・サイズなど)が表示されます。

    jcmd <process id/main class> VM.flags

  • 稼働時間(秒)の出力

    jcmd <process id/main class> VM.uptime

  • クラス・ヒストグラムの作成

    出力結果が冗長になる可能性があるので、出力をファイルにリダイレクトできます。内部クラスとアプリケーション固有のクラスの両方がリストに含まれます。メモリーの消費量が最も多いクラスから降順に表示されます。

    jcmd <process id/main class> GC.class_histogram

  • ヒープ・ダンプの作成

    jcmd GC.heap_dump filename=Myheapdump

    これはjmap -dump:file=<file> <pid>を使用する方法と同じですが、推奨ツールはjcmdです。

  • ヒープ・ヒストグラムの作成

    jcmd <process id/main class> GC.class_histogram filename=Myheaphistogram

    これはjmap -histo <pid>を使用する方法と同じですが、推奨ツールはjcmdです。

  • スタック・トレースのあるすべてのスレッドの出力

    jcmd <process id/main class> Thread.print

jcmdコマンド・ユーティリティを使用したトラブルシューティング

jcmdユーティリティを使用してトラブルシューティングします。

jcmdユーティリティでは、次のトラブルシューティング・オプションを使用できます。

  • 記録の開始

    たとえば、識別子が7060の実行中Javaプロセスで2分間の記録を開始し、それを現在のディレクトリのmyrecording.jfrに保存するには、次を使用します。

    jcmd 7060 JFR.start name=MyRecording settings=profile delay=20s duration=2m filename=C:\TEMP\myrecording.jfr

  • 記録の確認

    JFR.check診断コマンドは、実行中の記録を確認します。次に例を示します。

    jcmd 7060 JFR.check

  • 記録の停止

    JFR.stop診断コマンドは、実行中の記録を停止し、記録データを破棄することもできます。次に例を示します。

    jcmd 7060 JFR.stop

  • 記録のダンプ

    JFR.dump診断コマンドは、実行中の記録を停止し、記録をファイルにダンプすることもできます。次に例を示します。

    jcmd 7060 JFR.dump name=MyRecording filename=C:\TEMP\myrecording.jfr

  • ヒープ・ダンプの作成

    ヒープ・ダンプを作成する推奨方法を次に示します。

    jcmd <pid> GC.heap_dump filename=Myheapdump

  • ヒープ・ヒストグラムの作成

    ヒープ・ヒストグラムを作成する推奨方法を次に示します。

    jcmd <pid> GC.class_histogram filename=Myheaphistogram

ネイティブ・メモリー・トラッキング

ネイティブ・メモリー・トラッキング(NMT)は、Java HotSpot VMの内部メモリー使用状況を追跡するJava HotSpot VM機能です。

NMTでは、非JVMコードによるメモリーの割当てを追跡しないので、ネイティブ・コードのメモリー・リークを検出するには、オペレーティング・システムでサポートされたツールの使用が必要になる場合があります。

次の項では、VM内部メモリー割当てのモニターおよびVMメモリー・リークの診断方法について説明します。

NMTによるメモリー・リークの検出

ネイティブ・メモリー・トラッキングを使用してメモリー・リークを検知する手順。

メモリー・リークを検出するには、次の手順を実行します。

  1. 次のコマンドライン・オプションを使用して、サマリーまたは詳細なトラッキングが指定されたJVMを起動します: -XX:NativeMemoryTracking=summaryまたは-XX:NativeMemoryTracking=detail
  2. 初期のベースラインを設定します。NMTベースライン機能を使用して、開発とメンテナンスのときに比較するベースラインを取得するには、次を実行します: jcmd <pid> VM.native_memory baseline
  3. 次を使用して、メモリーの変更をモニターします: jcmd <pid> VM.native_memory detail.diff
  4. アプリケーションのメモリー・リークが少量の場合、それが明らかになるまで時間がかかる場合があります。

VM内部メモリーをモニターする方法

ネイティブ・メモリー・トラッキングはメモリーをモニターし、開発またはメンテナンス時にアプリケーションのメモリー使用量が増え始めないように設定できます。

NMTのメモリー・カテゴリの詳細は、表2-1を参照してください。

次の項では、NMTのサマリーまたは詳細データを取得する方法、およびサンプル出力の解釈の方法を説明します。

  • サンプル出力の解釈: 次のサンプル出力から、予約済メモリーとコミット済メモリーを確認できます。コミット済メモリーのみが実際に使用されることに注意してください。たとえば、-Xms100m -Xmx1000mで実行した場合、JVMでは1000MBがJavaヒープ用に予約されます。初期のヒープ・サイズは100MBのみであるため、最初に100MBのみがコミットされます。アドレス領域がほぼ無制限である64ビット・マシンの場合、JVMで多くのメモリーが予約されても問題はありません。コミットされるメモリーが次第に増加し、スワッピングやネイティブ・メモリー不足(OOM)状態になる可能性がある場合に、問題が発生します。

    アリーナは、mallocを使用して割り当てられるメモリー・チャンクです。スコープを終了またはコード領域を離れるとき、これらのチャンクからメモリーがバルクで解放されます。これらのチャンクは、一時メモリーを保持するために他のサブシステムで再利用できます(プリスレッドの割当てなど)。アリーナのmallocポリシーでは、メモリー・リークがないことが確認されます。したがって、個々のオブジェクトではなく、Arena全体が追跡されます。一部の初期メモリーは追跡できません。

    NMTを有効にすると、JVMパフォーマンスが5-10%低下し、NMTのメモリー使用量により、すべてのmallocメモリーに2マシン・ワードがmallocヘッダーとして追加されます。NMTのメモリー使用量も、NMTにより追跡されます。

    Total:  reserved=664192KB,  committed=253120KB                                           <--- total memory tracked by Native Memory Tracking
     
    -                 Java Heap (reserved=516096KB, committed=204800KB)                      <--- Java Heap
                                (mmap: reserved=516096KB, committed=204800KB)
     
    -                     Class (reserved=6568KB, committed=4140KB)                          <--- class metadata
                                (classes #665)                                               <--- number of loaded classes
                                (malloc=424KB, #1000)                                        <--- malloc'd memory, #number of malloc
                                (mmap: reserved=6144KB, committed=3716KB)
     
    -                    Thread (reserved=6868KB, committed=6868KB)
                                (thread #15)                                                 <--- number of threads
                                (stack: reserved=6780KB, committed=6780KB)                   <--- memory used by thread stacks
                                (malloc=27KB, #66)
                                (arena=61KB, #30)                                            <--- resource and handle areas
     
    -                      Code (reserved=102414KB, committed=6314KB)
                                (malloc=2574KB, #74316)
                                (mmap: reserved=99840KB, committed=3740KB)
     
    -                        GC (reserved=26154KB, committed=24938KB)
                                (malloc=486KB, #110)
                                (mmap: reserved=25668KB, committed=24452KB)
     
    -                  Compiler (reserved=106KB, committed=106KB)
                                (malloc=7KB, #90)
                                (arena=99KB, #3)
     
    -                  Internal (reserved=586KB, committed=554KB)
                                (malloc=554KB, #1677)
                                (mmap: reserved=32KB, committed=0KB)
     
    -                    Symbol (reserved=906KB, committed=906KB)
                                (malloc=514KB, #2736)
                                (arena=392KB, #1)
     
    -           Memory Tracking (reserved=3184KB, committed=3184KB)
                                (malloc=3184KB, #300)
     
    -        Pooled Free Chunks (reserved=1276KB, committed=1276KB)
                                (malloc=1276KB)
     
    -                   Unknown (reserved=33KB, committed=33KB)
                                (arena=33KB, #1)
  • 詳細データの取得: ネイティブ・メモリー使用量の詳細ビューを取得するには、次のコマンドライン・オプションを使用してJVMを起動します: -XX:NativeMemoryTracking=detailこれは、最も多くのメモリーを割り当てるメソッドを正確に追跡します。NMTを有効にすると、JVMパフォーマンスが5-10%低下し、NMTのメモリー使用量により、すべてのmallocメモリーに2ワードがmallocヘッダーとして追加されます。NMTのメモリー使用量も、NMTにより追跡されます。

    次の例は、追跡レベルが詳細に設定された仮想メモリーのサンプル出力を示しています。このサンプル出力を得るための1つの方法は、jcmd <pid> VM.native_memory detailを実行することです。

    Virtual memory map:
     
    [0x8f1c1000 - 0x8f467000] reserved 2712KB for Thread Stack
    		from [Thread::record_stack_base_and_size()+0xca]
    	[0x8f1c1000 - 0x8f467000] committed 2712KB from [Thread::record_stack_base_and_size()+0xca]
     
    [0x8f585000 - 0x8f729000] reserved 1680KB for Thread Stack
    		from [Thread::record_stack_base_and_size()+0xca]
    	[0x8f585000 - 0x8f729000] committed 1680KB from [Thread::record_stack_base_and_size()+0xca]
     
    [0x8f930000 - 0x90100000] reserved 8000KB for GC
    		from [ReservedSpace::initialize(unsigned int, unsigned int, bool, char*, unsigned int, bool)+0x555]
    	[0x8f930000 - 0x90100000] committed 8000KB from [PSVirtualSpace::expand_by(unsigned int)+0x95]
     
    [0x902dd000 - 0x9127d000] reserved 16000KB for GC
    		from [ReservedSpace::initialize(unsigned int, unsigned int, bool, char*, unsigned int, bool)+0x555]
    	[0x902dd000 - 0x9127d000] committed 16000KB from [os::pd_commit_memory(char*, unsigned int, unsigned int, bool)+0x36]
     
    [0x9127d000 - 0x91400000] reserved 1548KB for Thread Stack
    		from [Thread::record_stack_base_and_size()+0xca]
    	[0x9127d000 - 0x91400000] committed 1548KB from [Thread::record_stack_base_and_size()+0xca]
     
    [0x91400000 - 0xb0c00000] reserved 516096KB for Java Heap                                                                            <--- reserved memory range
    		from [ReservedSpace::initialize(unsigned int, unsigned int, bool, char*, unsigned int, bool)+0x190]                  <--- callsite that reserves the memory
    	[0x91400000 - 0x93400000] committed 32768KB from [VirtualSpace::initialize(ReservedSpace, unsigned int)+0x3e8]               <--- committed memory range and its callsite
    	[0xa6400000 - 0xb0c00000] committed 172032KB from [PSVirtualSpace::expand_by(unsigned int)+0x95]                             <--- committed memory range and its callsite
     
    [0xb0c61000 - 0xb0ce2000] reserved 516KB for Thread Stack
    		from [Thread::record_stack_base_and_size()+0xca]
    	[0xb0c61000 - 0xb0ce2000] committed 516KB from [Thread::record_stack_base_and_size()+0xca]
     
    [0xb0ce2000 - 0xb0e83000] reserved 1668KB for GC
    		from [ReservedSpace::initialize(unsigned int, unsigned int, bool, char*, unsigned int, bool)+0x555]
    	[0xb0ce2000 - 0xb0cf0000] committed 56KB from [PSVirtualSpace::expand_by(unsigned int)+0x95]
    	[0xb0d88000 - 0xb0d96000] committed 56KB from [CardTableModRefBS::resize_covered_region(MemRegion)+0xebf]
    	[0xb0e2e000 - 0xb0e83000] committed 340KB from [CardTableModRefBS::resize_covered_region(MemRegion)+0xebf]
     
    [0xb0e83000 - 0xb7003000] reserved 99840KB for Code
    		from [ReservedSpace::initialize(unsigned int, unsigned int, bool, char*, unsigned int, bool)+0x555]
    	[0xb0e83000 - 0xb0e92000] committed 60KB from [VirtualSpace::initialize(ReservedSpace, unsigned int)+0x3e8]
    	[0xb1003000 - 0xb139b000] committed 3680KB from [VirtualSpace::initialize(ReservedSpace, unsigned int)+0x37a]
     
    [0xb7003000 - 0xb7603000] reserved 6144KB for Class
    		from [ReservedSpace::initialize(unsigned int, unsigned int, bool, char*, unsigned int, bool)+0x555]
    	[0xb7003000 - 0xb73a4000] committed 3716KB from [VirtualSpace::initialize(ReservedSpace, unsigned int)+0x37a]
     
    [0xb7603000 - 0xb760b000] reserved 32KB for Internal
    		from [PerfMemory::create_memory_region(unsigned int)+0x8ba]
     
    [0xb770b000 - 0xb775c000] reserved 324KB for Thread Stack
    		from [Thread::record_stack_base_and_size()+0xca]
    	[0xb770b000 - 0xb775c000] committed 324KB from [Thread::record_stack_base_and_size()+0xca]
  • NMTベースラインからの差分の取得: サマリーおよび詳細レベルの追跡では、アプリケーションが起動され実行された後、ベースラインを設定できます。これを行うには、アプリケーションのウォーム・アップ後にjcmd <pid> VM.native_memory baselineを実行します。次に、jcmd <pid> VM.native_memory summary.diffまたはjcmd <pid> VM.native_memory detail.diffを実行できます。

    次の例は、ベースラインの設定以降に使用されたネイティブ・メモリーの差分サマリーのサンプル出力を示し、これはメモリー・リークを見つけるのに優れた方法です。

    Total:  reserved=664624KB  -20610KB, committed=254344KB -20610KB                         <--- total memory changes vs. earlier baseline. '+'=increase '-'=decrease
     
    -                 Java Heap (reserved=516096KB, committed=204800KB)
                                (mmap: reserved=516096KB, committed=204800KB)
     
    -                     Class (reserved=6578KB +3KB, committed=4530KB +3KB)
                                (classes #668 +3)                                            <--- 3 more classes loaded
                                (malloc=434KB +3KB, #930 -7)                                 <--- malloc'd memory increased by 3KB, but number of malloc count decreased by 7
                                (mmap: reserved=6144KB, committed=4096KB)
     
    -                    Thread (reserved=60KB -1129KB, committed=60KB -1129KB)
                                (thread #16 +1)                                              <--- one more thread
                                (stack: reserved=7104KB +324KB, committed=7104KB +324KB)
                                (malloc=29KB +2KB, #70 +4)
                                (arena=31KB -1131KB, #32 +2)                                 <--- 2 more arenas (one more resource area and one more handle area)
     
    -                      Code (reserved=102328KB +133KB, committed=6640KB +133KB)
                                (malloc=2488KB +133KB, #72694 +4287)
                                (mmap: reserved=99840KB, committed=4152KB)
     
    -                        GC (reserved=26154KB, committed=24938KB)
                                (malloc=486KB, #110)
                                (mmap: reserved=25668KB, committed=24452KB)
     
    -                  Compiler (reserved=106KB, committed=106KB)
                                (malloc=7KB, #93)
                                (arena=99KB, #3)
     
    -                  Internal (reserved=590KB +35KB, committed=558KB +35KB)
                                (malloc=558KB +35KB, #1699 +20)
                                (mmap: reserved=32KB, committed=0KB)
     
    -                    Symbol (reserved=911KB +5KB, committed=911KB +5KB)
                                (malloc=519KB +5KB, #2921 +180)
                                (arena=392KB, #1)
     
    -           Memory Tracking (reserved=2073KB -887KB, committed=2073KB -887KB)
                                (malloc=2073KB -887KB, #84 -210)
     
    -        Pooled Free Chunks (reserved=2624KB -15876KB, committed=2624KB -15876KB)
                                (malloc=2624KB -15876KB)

    次の例は、ベースライン以降に使用されたネイティブ・メモリーの差分詳細を示すサンプル出力で、これはメモリー・リークを見つけるのに優れた方法です。

    Details:
     
    [0x01195652] ChunkPool::allocate(unsigned int)+0xe2
                                (malloc=482KB -481KB, #8 -8)
     
    [0x01195652] ChunkPool::allocate(unsigned int)+0xe2
                                (malloc=2786KB -19742KB, #134 -618)
     
    [0x013bd432] CodeBlob::set_oop_maps(OopMapSet*)+0xa2
                                (malloc=591KB +6KB, #681 +37)
     
    [0x013c12b1] CodeBuffer::block_comment(int, char const*)+0x21                <--- [callsite address] method name + offset
                                (malloc=562KB +33KB, #35940 +2125)               <--- malloc'd amount, increased by 33KB #malloc count, increased by 2125
     
    [0x0145f172] ConstantPool::ConstantPool(Array<unsigned char>*)+0x62
                                (malloc=69KB +2KB, #610 +15)
     
    ...
     
    [0x01aa3ee2] Thread::allocate(unsigned int, bool, unsigned short)+0x122
                                (malloc=21KB +2KB, #13 +1)
     
    [0x01aa73ca] Thread::record_stack_base_and_size()+0xca
                                (mmap: reserved=7104KB +324KB, committed=7104KB +324KB)

JConsole

JDKダウンロードに含まれるもう1つの便利なツールは、JConsoleモニタリング・ツールです。このツールはJMXに準拠しています。このツールは、JVMの組込みJMXインストゥルメンテーションを使用して、実行中のアプリケーションのパフォーマンスやリソース消費に関する情報を提供します。

このツールは、JDKダウンロードに含まれてはいますが、JREで配備されたアプリケーションのモニターや管理にも使用できます。

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

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

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

次の項では、JConsoleツールによるトラブルシューティング手法について説明します。

JConsoleツールによるトラブルシューティング

JConsoleを使用して、データをモニターします。

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

  • 概要

    このペインには、ヒープ・メモリー使用量、スレッド数、クラス数、およびCPU使用率の経時的推移を示すグラフが表示されます。この概要では、いくつかのリソースのアクティビティを一度に視覚化できます。

  • メモリー

    • 選択された1つのメモリー領域(ヒープ、非ヒープ、各種メモリー・プール)について

      • メモリー使用量の経時的推移を示すグラフ

      • 現在のメモリー・サイズ

      • コミットされたメモリーの量

      • 最大メモリー・サイズ

    • ガベージ・コレクタの情報(実行されたコレクションの回数や、ガベージ・コレクションの実行に費やされた合計時間など)

    • 現在使用中のヒープおよび非ヒープ・メモリーのパーセントを示すグラフ

    さらにこのペインでは、ガベージ・コレクションの実行を要求できます。

  • スレッド

    • スレッド使用量の経時的推移を示すグラフ。

    • ライブ・スレッド: 現在のライブ・スレッド数。

    • ピーク: JVM起動後のライブ・スレッドの最大数。

    • 選択された1つのスレッドの名前、状態、およびスタック・トレース、およびブロックされたスレッドの場合は、スレッドが獲得を待機しているシンクロナイザとロックを所有しているスレッド。

    • デッドロックの検出」ボタンは、デッドロック検出を実行する要求をターゲット・アプリケーションに送信し、各デッドロック・サイクルをそれぞれ異なるタブに表示します。

  • クラス

    • ロード済クラス数の経時的推移を示すグラフ

    • 現在メモリーにロードされているクラスの数

    • JVMの起動後にメモリーにロードされたクラスの合計数(その後アンロードされたものも含む)

    • JVMの起動後にメモリーからアンロードされたクラスの合計数

  • VMサマリー

    • 一般的な情報(JConsole接続データ、JVMの稼働時間、JVMで消費されたCPU時間、コンパイラ名、合計コンパイル時間など)。

    • スレッドおよびクラスのサマリー情報

    • メモリーおよびガベージ・コレクションの情報(ファイナライズ保留中のオブジェクトの数など)

    • オペレーティング・システムに関する情報(物理特性、実行中のプロセス用の仮想メモリー量、スワップ領域など)

    • JVM自体に関する情報(引数やクラス・パスなど)

  • MBeans

    このペインには、接続済のJMXエージェントに登録されたすべてのプラットフォームおよびアプリケーションMBeanを示すツリー構造が表示されます。ツリー内でMBeanを選択すると、その属性、操作、通知、およびその他の情報が表示されます。

    • 操作(存在する場合)を呼び出せます。たとえば、com.sun.managementドメインに含まれるHotSpotDiagnostic MBeanの操作dumpHeapは、ヒープ・ダンプを実行します。この操作の入力パラメータは、ターゲットVMが実行されているマシン上でのヒープ・ダンプ・ファイルのパス名になります。

    • 書込み可能な属性値を設定できます。たとえば、特定のVMフラグの値を設定、設定解除、または変更するには、HotSpotDiagnostic MBeanのsetVMOption操作を呼び出します。フラグは、DiagnosticOptions属性の値のリストによって示されます。

    • 通知(存在する場合)をサブスクライブするには、「サブスクライブ」および「サブスクライブ解除」ボタンを使用します。

JConsoleによるローカルおよびリモート・アプリケーションのモニター

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

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

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

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

最新のJDKリリースでは、モニター対象アプリケーションを起動する際にオプションは不要です。

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

図2-15 JConsoleからのサンプル出力

図2-15の説明が続きます
「図2-15 JConsoleからのサンプル出力」の説明

jdbユーティリティ

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

$JAVA_HOME/demo/jpda/examples.jarにはjdbのソース・コードが含まれています。

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

次の項では、jdbユーティリティのトラブルシューティング手法を提供します。

jdbユーティリティによるトラブルシューティング

jdbユーティリティはリモート・デバッグに使用するデバッガ・コネクタをモニターするために使用します。

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

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

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

これらのコネクタは通常、NetBeans統合開発環境(IDE)や商用IDEなどのエンタープライズ・デバッガで使用されます。次の項では、jdbコマンド行デバッガでこれらのコネクタを使用する方法を示します。

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

Java Platform, Standard Editionツール・リファレンスのjdbユーティリティに関する項を参照してください

プロセスの接続

次の例では、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コマンドを再度使用してスレッド・ダンプを取得しています。

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

SAコア接続コネクタは、デバッガをコア・ファイルに接続するために使用されます。

クラッシュの後にコア・ファイルが作成されている場合があります。「システム・クラッシュのトラブルシューティング」を参照してください。コア・ファイルは、gcoreコマンド(Oracle Solarisオペレーティング・システムの場合)、またはgdbgcoreコマンド(Linuxの場合)を使用して取得することもできます。コア・ファイルはそのコア・ファイルが作成された時点のプロセスのスナップショットであるため、コネクタは読取り専用モードで接続します。つまり、デバッガはクラッシュ発生時のスレッドや実行中のアプリケーションを調べることができます。

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

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

別のマシンからのコア・ファイルまたはハング・プロセスへの接続

デバッガがインストールされたマシン上で、SAデバッグ・サーバー接続コネクタを使用してデバッグ・サーバーに接続できます。

別のマシンからトランスポートされたコア・ファイルをデバッグするには、オペレーティング・システムのバージョンとライブラリが一致する必要があります。この場合はまず、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デバッグ・サーバーはハングアップ・プロセスのリモート・デバッグにも使用できます。その場合、単一の引数(プロセスのPID)を取ります。さらに、同じマシン上で複数のデバッグ・サーバーを実行する必要がある場合は、それぞれに一意のIDを指定する必要があります。SAデバッグ・サーバー接続コネクタで、このIDは追加のコネクタ引数として提供されます。

jinfoユーティリティ

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

JVMおよびJavaアプリケーションに関する問題を診断するには、Java Mission Control、Java Flight Recorderおよびjcmdユーティリティを使用できます。診断機能を強化し、パフォーマンスのオーバーヘッドを削減するには、以前のjinfoユーティリティのかわりに最新のユーティリティjcmdを使用してください。

jinfoユーティリティでは、jsadebugdデーモンを使用してリモート・マシン上のプロセスやコア・ファイルを照会することもできます。

注意:

この場合、出力に時間がかかります。

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

次の例は、PID番号が29620のJavaプロセスのjinfoユーティリティの出力を示しています。

$ 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:

次のトピックでは、jinfoユーティリティによるトラブルシューティング手法について説明します。

jinfoユーティリティによるトラブルシューティング

jinfoの出力には、java.class.pathおよびsun.boot.class.pathの設定が表示されます。

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

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

$ jinfo $JAVA_HOME/bin/java core.29620

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

jmapユーティリティ

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

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

JVMおよびJavaアプリケーションに関する問題を診断するには、Java Mission Control、Java Flight Recorderおよびjcmdユーティリティを使用できます。診断機能を強化し、パフォーマンスのオーバーヘッドを削減するには、以前のjmapユーティリティのかわりに最新のユーティリティjcmdの使用をお薦めします。

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

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

ハングアップ・プロセスが原因でjmappidコマンドが反応しない場合は、-Fオプションを使用して(Oracle SolarisおよびLinuxオペレーティング・システムのみ) Serviceability Agentの使用を強制できます。

次の項では、jmapコマンドの使用方法およびトラブルシューティング手法について説明し、実行中のVMまたはコア・ファイルのメモリー関連の統計情報を出力する例を示します。

ヒープの構成と使用量

jmap -heapコマンドを使用してJavaヒープ情報を取得します。

次のJavaヒープ情報を取得するには、-heapオプションを使用します。

  • ガベージ・コレクション(GC)アルゴリズムに固有の情報。GCアルゴリズムの名前(パラレルGCなど)やアルゴリズム固有の詳細(パラレルGCのスレッド数など)が含まれます。

  • コマンド行オプションとして指定されたか、またはマシンの構成に基づいてVMによって選択された可能性のあるヒープ構成。

  • ヒープ使用量のサマリー: このツールは、各世代(ヒープ領域)について、合計ヒープ容量、使用中のメモリー、および使用可能な空きメモリーを出力します。領域の集まりとして構成された世代(New世代など)では、領域固有のメモリー・サイズ・サマリーが含まれます。

次の例は、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

ヒープ・ヒストグラム

-histoオプションを指定してjmapコマンドを使用すると、クラス固有のヒープ・ヒストグラムを取得できます。

指定されたパラメータに応じて、jmap -histoコマンドは実行中のプロセスまたはコア・ファイルのヒープ・ヒストグラムを出力できます。

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

次の例は、29620というPID番号を持つプロセスに対して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

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

jmap -histoコマンドをコア・ファイルで実行した場合の出力を示します。

& 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...

Permanent世代の統計

Permanent世代は、クラスやメソッド・オブジェクトなどの仮想マシン自体を反映したデータをすべて保持するヒープ領域です。

この領域は、Java仮想マシン仕様ではメソッド領域とも呼ばれます。

非常に多くのクラスを動的に生成してロードするアプリケーション(Java Server PagesやWebコンテナなど)では、Permanent世代のサイズの構成が重要になる可能性があります。アプリケーションでロードされたクラスが多すぎた場合、そのアプリケーションは次のエラーで終了する可能性があります。

Exception in thread thread_name java.lang.OutOfMemoryError: PermGen space

OutOfMemoryError例外の理解」を参照してください。

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

次の例は、29620というPID番号を持つプロセスに対して実行された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    

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

  • クラス・ローダー・オブジェクトのアドレス(ユーティリティが実行されたスナップショット時点)

  • ロードされたクラスの数

  • このクラス・ローダーによってロードされたすべてのクラスのメタデータで消費されているバイト数(概算)

  • 親クラス・ローダー(存在する場合)のアドレス

  • ローダー・オブジェクトが将来ガベージ・コレクトされるかどうかを示すliveまたはdeadマーク

  • このクラス・ローダーのクラス名

jpsユーティリティ

jpsユーティリティは、ターゲット・システム上の現在のユーザーで計測されたすべてのJava HotSpot VMを一覧表示します。

VMが埋め込まれた環境、つまりjava起動ツールではなくJNI呼出しAPIを使用してVMが起動される環境では、このユーティリティが非常に役立ちます。こうした環境では、プロセス・リスト内でJavaプロセスを認識するのが常に容易であるとはかぎりません。

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

$ jps
16217 MyApplication
16342 jps

jpsユーティリティは、ユーザーがアクセス権を持つ仮想マシンを一覧表示します。この判断には、オペレーティング・システムに固有のアクセス制御メカニズムが使用されます。たとえば、Oracle Solarisオペレーティング・システム上のroot以外のユーザーがjpsユーティリティは、ユーザーがアクセス権を持つ仮想マシンを一覧表示します。ユーティリティを実行した場合、出力はそのユーザーのUIDで起動された仮想マシンの一覧になります。

このユーティリティには、PIDの一覧表示に加え、アプリケーションのmainメソッドに渡された引数、VM引数の完全なリスト、アプリケーションのmainクラスの完全なパッケージ名を出力するオプションも用意されています。また、リモート・システム上で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

jstackユーティリティ

JVMおよびJavaアプリケーションの問題を診断するには、jstackユーティリティではなくjcmdユーティリティを使用してください。

JVMおよびJavaアプリケーションに関する問題を診断するには、Java Mission Control、Java Flight Recorderおよびjcmdユーティリティを使用できます。診断機能を強化し、パフォーマンスのオーバーヘッドを削減するには、以前のjstack,ユーティリティのかわりに最新のユーティリティjcmdの使用をお薦めします。

次の項では、jstackユーティリティによるトラブルシューティング手法について説明します。

jstackユーティリティによるトラブルシューティング

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

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

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

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

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

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

コア・ダンプからのスタック・トレース

コア・ダンプからスタック・トレースを取得するにはjstackコマンドを使用します。

コア・ダンプからスタック・トレースを取得するには、次の例のように、コア・ファイルでjstackコマンドを実行します。

$ jstack $JAVA_HOME/bin/java core

混合スタック

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++分解シンボル名を分解解除できます。Java HotSpot VMはC++言語で開発されているため、jstackユーティリティはJava HotSpotの内部関数のC++分解シンボル名を出力します。

c++filtユーティリティは、SUNWspro (Oracle Solarisオペレーティング・システムの場合)やgnu (Linuxの場合)というネイティブC++コンパイラ・スイートとともに配布されます。

jstatユーティリティ

jstatユーティリティは、Java HotSpot VMの組込みインストゥルメンテーションを使用して、実行中アプリケーションのパフォーマンスやリソース消費に関する情報を提供します。

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

注意:

FAT32ファイル・システム上では、インストゥルメンテーションにアクセスできません。

Java Platform, Standard Editionツール・リファレンスのjstatに関する項を参照してください。

jstatユーティリティは、仮想マシン識別子(VMID)を使用してターゲット・プロセスを識別します。ドキュメントにはVMIDの構文が記載されていますが、それに必要な唯一のコンポーネントはローカル仮想マシン識別子(LVMID)です。LVMIDは、(必ずではありませんが、)一般的にはターゲットJVMプロセスに対するオペレーティング・システムのPIDです。

jstatユーティリティで提供されるデータは、Oracle SolarisおよびLinuxオペレーティング・システムのvmstatおよびiostatで提供されるデータに似ています。

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

-gcutilオプションの使用例を次に示します。この例では、jstatユーティリティがLVMID番号2834に接続し、250ミリ秒間隔で7つのサンプルを取っています。

$ jstat -gcutil 2834 250 7
  S0     S1     E      O      M     YGC     YGCT    FGC    FGCT     GCT   
  0.00  99.74  13.49   7.86  95.82      3    0.124     0    0.000    0.124
  0.00  99.74  13.49   7.86  95.82      3    0.124     0    0.000    0.124
  0.00  99.74  13.49   7.86  95.82      3    0.124     0    0.000    0.124
  0.00  99.74  13.49   7.86  95.82      3    0.124     0    0.000    0.124
  0.00  99.74  13.49   7.86  95.82      3    0.124     0    0.000    0.124
  0.00  99.74  13.49   7.86  95.82      3    0.124     0    0.000    0.124
  0.00  99.74  13.49   7.86  95.82      3    0.124     0    0.000    0.124

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

-gcnewオプションの使用例を次に示します。この例では、jstatユーティリティが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領域1の使用率(S1U)が適切なSurvivorサイズ(DSS)を超過するのに十分なライブ・データが検出されました。この結果、オブジェクトは、Old世代(この出力には非表示)へ昇格され、殿堂入りしきい値(TT)が、15から1へ降格されました。

-gcoldcapacityオプションの使用例を次に示します。この例では、jstatユーティリティが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列には、ターゲットJVMの起動時からの経過時間が、秒単位で報告されています。さらに、-gcoldcapacity出力では、割当て要求または昇格要求あるいはその両方を満たすためにヒープが拡張するたびに、Old世代の容量(OGC)とOld領域の容量(OC)とが増加していることがわかります。OGCは、81番目の全世代の容量(FGC)後に、11696 KBから13820 KBへ増加しています。この世代(および領域)の最大容量は、60544 Kバイト(OGCMX)なので、まだ拡張できる余裕が残されています。

visualgcツール

visualgcツールは、ガベージ・コレクション(GC)システムのグラフィカル表示を提供します。

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

visualgcツールはJDKリリースには含まれていませんが、jvmstatテクノロジ・ページから個別のダウンロードとして入手できます。

図2-16は、GCおよびヒープの視覚化を示しています。

図2-16 visualgcからのサンプル出力

図2-16の説明が続きます
「図2-16 visualgcからのサンプル出力」の説明

Ctrl+Breakハンドラ

Oracle Solaris、Linux、Windowsなどのオペレーティング・システムのアプリケーション・コンソールで[Ctrl]キーとバックスラッシュ([\])キーを押したときの結果。

Oracle SolarisまたはLinuxオペレーティング・システムの場合、アプリケーション・コンソール(標準入力)で[Ctrl]キーとバックスラッシュ([\])キーの組合せを押すと、Java HotSpot VMからアプリケーションの標準出力にスレッド・ダンプが出力されます。Windowsの場合、同等のキー・シーケンスは[Ctrl]キーと[Break]キーです。これらのキーの組合せを表す一般的な用語は、Ctrl+Breakハンドラです。

Oracle SolarisおよびLinuxオペレーティング・システムでは、Javaプロセスがquitシグナルを受信するとスレッド・ダンプが出力されます。したがって、kill -QUIT pidコマンドを実行すると、pidをIDに持つプロセスから標準出力にスレッド・ダンプが出力されます。

次の項では、Ctrl+Breakハンドラによってトレースされるデータについて説明します。

スレッド・ダンプ

スレッド・ダンプは、仮想マシン内のすべての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内部スレッドに関する情報が続きます。各スレッド・エントリは、ヘッダー行とその後に続くスレッド・スタック・トレースで構成されます。

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

  • スレッド名

  • スレッドがデーモン・スレッドかどうかのマーク

  • スレッド優先度(prio)

  • スレッドID (tid)。メモリー内のスレッド構造体のアドレスです

  • ネイティブ・スレッドのID (nid)

  • スレッド・ダンプ時にスレッドが実行していた内容を示す、スレッド状態詳細は、表2-6を参照してください。

  • アドレス範囲(スレッドのおおよその有効なスタック領域を表す)

デッドロックの検出

Ctrl+Breakハンドラは、スレッドのデッドロック検出にも使用できます。

Ctrl+Breakハンドラは、スレッド・スタックだけでなく、デッドロック検出アルゴリズムも実行します。デッドロックが検出された場合、次の例に示すように、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.

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

ヒープ・サマリー

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)

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

オペレーティング・システムのネイティブ・ツール

Windows、LinuxおよびOracle Solarisオペレーティング・システムで使用可能なネイティブ・ツールのうち、トラブルシューティングやモニタリングの目的で役立つもののリスト。

各ツールについて簡単な説明が提供されます。詳細は、オペレーティング・システムのマニュアル(またはOracle SolarisおよびLinuxオペレーティング・システムのマニュアル・ページ)を参照してください。

コマンド行ユーティリティからのログ・ファイルや出力の形式は、リリースごとに異なります。たとえば、致命的エラー・ログの形式に依存するスクリプトを開発した場合、そのログ・ファイルの形式が将来のリリースで変更されれば、同じスクリプトでも動作しなくなる可能性があります。

Windows固有のデバッグ・サポートは、MSDN Developer Networkで検索することもできます。

次の項では、いくつかのオペレーティング・システム・ツールのトラブルシューティング手法および改善について説明します。

DTraceツール

Oracle Solaris 10オペレーティング・システムに含まれるDTraceツールを使用すれば、オペレーティング・システムのカーネルおよびユーザー・レベルのプログラムの動的トレースを行えます。

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

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

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

これらのプローブは、プロバイダと呼ばれるカーネル・モジュールによって配布され計測されます。プローブ・プロバイダによって提供されるトレースのタイプには、ユーザー命令トレース、関数境界トレース、カーネル・ロック計測、プロファイル割込み、システム・コール・トレースなどがあり、その他にもたくさんあります。独自のスクリプトを記述する場合は、D言語を使用してそれらのプローブを有効にします。この言語では、条件付きトレースや出力のフォーマットも可能です。

dtrace -lコマンドを使用すると、使用しているOracle Solarisオペレーティング・システムで使用可能な一連のプロバイダやプローブを調べることができます。

DTraceToolkitは、Oracle Solaris DTraceのオープン・コミュニティで開発されたドキュメント付きの有用なスクリプトを集めたものです。DTraceToolkitに関する項を参照してください。

Solaris動的トレース・ガイドを参照してください。

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

Java HotSpot VMにはhotspotおよびhotspot_jniという2つの組込みプローブ・プロバイダが含まれるようになりました。

これらのプロバイダは、VMの内部状態やアクティビティだけでなく、実行中のJavaアプリケーションもモニターするために使用できるプローブを配布します。

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

  • VMのライフ・サイクル: VMの初期化の開始と終了、およびVMのシャットダウン

  • スレッドのライフ・サイクル: スレッドの開始と停止、スレッド名、スレッドIDなど

  • クラスのロード: Javaクラスのロードとアンロード

  • ガベージ・コレクション: ガベージ・コレクションの開始と停止、システム全体またはメモリー・プール別

  • メソッドのコンパイル: メソッドのコンパイルの開始と終了、メソッドのロードとアンロード

  • モニター・プローブ: 待機イベント、通知イベント、競合するモニターへの出入り

  • アプリケーションの追跡: メソッドに入る、メソッドから戻る、Javaオブジェクトの割当て

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

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

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

前の例のスクリプトはread.dというファイルに格納され、次の例に示すように、トレース対象のJavaプロセスのPIDを指定することで実行されます。

read.d pid

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

pmapユーティリティの改善

Oracle Solaris 10オペレーティング・システムのpmapユーティリティの改善。

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

次の例は、改善されたpmapユーティリティによるスタック・トレースを示しています。

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

pstackユーティリティの改善

Oracle Solaris 10オペレーティング・システムのpstackユーティリティの改善。

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

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

カスタム診断ツール

JDKには、JREに配備されているアプリケーションの問題を観察、モニター、プロファイル、デバッグ、および診断するカスタム・ツールを開発するための広範なAPIが含まれています。

新しいツールの開発はこのドキュメントの対象外です。かわりにこのセクションでは、使用可能なAPIの概要を簡単に説明します。

この項に示されたすべてのパッケージは、Java SE API仕様で説明されています。

JDKダウンロードに含まれるコード例やデモ・コードを参照してください。

次の項では、トラブルシューティングのためのカスタム診断ツールとして使用できるパッケージ、インタフェース・クラスおよびJavaデバッガについて説明します。

Java Platform Debugger Architecture

Java Platform Debugger Architecture (JPDA)は、デバッガやデバッガに似たツールが使用するために設計されたアーキテクチャです。

Java Platform Debugger Architectureは、2つのプログラミング・インタフェースおよびワイヤ・プロトコルで構成されています。

  • Java Virtual Machine Tool Interface (JVM TI)は、仮想マシンへのインタフェースです。「JVM Tool Interface」を参照してください。

  • Java Debug Interface (JDI)は、ユーザー・コード・レベルでの情報および要求を定義します。これは、Javaプログラミング言語アプリケーションをデバッグするためのPure Javaプログラミング言語インタフェースです。JPDAでは、JDIは、デバッガのプロセスから見たデバッグ対象プロセスの仮想マシンのリモート・ビューです。これはフロント・エンドによって実装されます。デバッガに似たアプリケーション(IDE、デバッガ、トレーサ、モニタリング・ツールなど)はクライアントとなります。モジュールjdk.jdiを参照してください。

  • Java Debug Wire Protocol (JDWP)は、デバッグされるプロセスと、JDIを実装したデバッガ・フロント・エンドとの間で転送される、情報および要求の形式を定義します。

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

JDIを使用すれば、従来のデバッガ・タイプのツールだけでなく、ポストモーテム診断の際や、ツールが非協力的なプロセス(ハングアップ・プロセスなど)に接続する必要があるシナリオで役に立つツールを開発することもできます。

NMTのメモリー・カテゴリ

NMTで使用されるネイティブ・メモリー・トラッキングのメモリー・カテゴリのリスト。

表2-1に、NMTで使用されるネイティブ・メモリー・カテゴリを示します。これらのカテゴリは、リリースにより変更される可能性があります。

表2-1 ネイティブ・メモリー・トラッキングのメモリー・カテゴリ

カテゴリ 説明

Javaヒープ

オブジェクトが存在するヒープ

クラス

クラス・メタデータ

コード

生成されたコード

GC

カード表など、GCにより使用されるデータ

コンパイラ

コードを生成するときにコンパイラによって使用されるメモリー・トラッキング

記号

記号

メモリー・トラッキング

NMTによって使用されるメモリー。

空きチャンク・プール

アリーナのチャンク・プール内のチャンクによって使用されるメモリー

クラスの共有領域

クラス・データ共有アーカイブにマップされるメモリー

スレッド

スレッド・データ構造、リソース領域、ハンドル領域などを含む、スレッドによって使用されるメモリー。

スレッド・スタック

スレッド・スタック。コミットされたメモリーとしてマークされますが、OSによって完全にコミットされない場合があります

内部

コマンドライン・パーサー、JVMTI、プロパティおよびその他によって使用されるメモリーなど、前述のカテゴリに該当しないメモリー。

不明

メモリーのカテゴリを決定できない場合。

アリーナ: スタックまたは値オブジェクトとしてアリーナが使用されている場合

仮想メモリー: タイプ情報がまだ到着していない場合

ポストモーテム診断ツール

アプリケーションとJava HotSpot VMとの間で発生する問題のポストモーテム診断用に使用可能なツールとオプションのリスト。

表2-2に、ポストモーテム診断用に設計されたオプションおよびツールの要約を示します。アプリケーションがクラッシュした場合、これらのオプションやツールを使用して、クラッシュ発生時、または後でクラッシュ・ダンプからの情報を使用して追加情報を取得できます。

表2-2 ポストモーテム診断ツール

ツールまたはオプション 説明および使用方法

致命的エラー・ログ

回復不能(致命的)なエラーが発生すると、エラー・ログが作成されます。このファイルには、致命的エラーの発生時に取得された情報が含まれています。これは多くの場合、クラッシュ発生時に最初に調べる必要がある項目です。「致命的エラー・ログ」を参照してください。

-XX:+HeapDumpOnOutOfMemoryErrorオプション

このコマンド行オプションは、VMでネイティブのメモリー不足エラーが検出された際にヒープ・ダンプを生成することを指定します。「-XX:HeapDumpOnOutOfMemoryErrorオプション」を参照してください。

-XX:OnErrorオプション

このコマンド行オプションは、致命的エラーの発生時にユーザー指定の一連のスクリプトまたはコマンドを実行することを指定します。たとえばWindowsの場合、このオプションでクラッシュ・ダンプを強制するコマンドを実行できます。ポストモーテム・デバッガが構成されていないシステムでは、このオプションが非常に役立ちます。「-XX:OnErrorオプション」を参照してください。

-XX:+ShowMessageBoxOnErrorオプション

このコマンド行オプションは、致命的エラーの発生時にプロセスを中断します。このオプションはユーザーの応答に応じて、ネイティブ・デバッガ(dbxgdbmsdev)を起動してVMに接続できます。「-XX:ShowMessageBoxOnErrorオプション」を参照してください。

その他の-XXオプション

トラブルシューティングに役立つ-XXコマンド行オプションは、ほかにもいくつかあります。「その他の-XX Optionsオプション」を参照してください。

jdbユーティリティ

デバッガ・サポートには、jdbなどのJava言語デバッガがコア・ファイルに接続することを許可する、AttachingConnectorが含まれています。これは、各スレッドがクラッシュ時に何をしていたのかを理解しようとする際に役立つ可能性があります。「jdbユーティリティ」を参照してください。

jinfoユーティリティ

(Oracle SolarisおよびLinuxオペレーティング・システムでのみ使用されるポストモーテム)

このユーティリティは、クラッシュから取得されたコア・ファイル、またはgcoreユーティリティを使用して取得されたコア・ファイルから、構成情報を取得できます。「jinfoユーティリティ」を参照してください。

jmapユーティリティ

(Oracle SolarisおよびLinuxオペレーティング・システムでのみ使用されるポストモーテム)

このユーティリティは、クラッシュから取得されたコア・ファイルから、またはgcoreユーティリティを使用して取得されたコア・ファイルから、ヒープ・ヒストグラムなどのメモリー・マップ情報を取得できます。「jmapユーティリティ」を参照してください。

jsadebugdデーモン

(Oracle SolarisおよびLinuxオペレーティング・システムのみ)

Serviceability Agent Debug Daemon (jsadebugd)は、Javaプロセスまたはコア・ファイルに接続し、デバッグ・サーバーとして動作します。「jsadebugdデーモン」を参照してください。

jstackユーティリティ

このユーティリティは、JavaプロセスからJavaおよびネイティブ・スタックの情報を取得できます。Oracle SolarisおよびLinuxオペレーティング・システムでは、コア・ファイルまたはリモート・デバッグ・サーバーからも情報を取得できます。「jstackユーティリティ」を参照してください。

ネイティブ・ツール

各オペレーティング・システムには、ポストモーテム診断に使用可能なネイティブ・ツールおよびユーティリティがあります。「オペレーティング・システムのネイティブ・ツール」を参照してください。

ハングアップ・プロセス・ツール

ハングアップ・プロセスでアプリケーションとJava HotSpot VMとの間で発生する問題を診断するためのツールとオプションのリスト。

表2-3では、ハングアップまたはデッドロックしたプロセスに関連するシナリオで役立つ可能性のあるオプションやツールをまとめています。これらのツールでは、アプリケーション起動時に特殊なオプションは必要ありません。

JVMおよびJavaアプリケーションに関する問題を診断するには、Java Mission Control、Java Flight Recorderおよびjcmdユーティリティを使用できます。診断機能を強化し、パフォーマンスのオーバーヘッドを削減するには、以前のjstack,、jinfoおよびjmapユーティリティのかわりに最新の診断ツールjcmdの使用をお薦めします。

表2-3 ハングアップ・プロセス・ツール

ツールまたはオプション 説明および使用方法

Ctrl+Breakハンドラ

(Oracle SolarisおよびLinuxオペレーティング・システムでは[Ctrl]+[\]またはkill -QUIT pid、Windowsでは[Ctrl]+[Break])

このキーの組合せでは、スレッド・ダンプとデッドロック検出が実行されます。Ctrl+Breakハンドラではオプションで、並行ロックとその所有者の一覧や、ヒープ・ヒストグラムを出力することもできます。「Ctrl+Breakハンドラ」を参照してください。

jcmdユーティリティ

このユーティリティを使用してJVMに診断コマンド・リクエストを送信し、JVMではこれらのリクエストを使用してJavaフライト記録(JFR)を制御します。JFRはフライト記録のイベントのトラブルシューティングと診断に使用します。「jcmdユーティリティ」を参照してください。

jdbユーティリティ

デバッガ・サポートには、jdbなどのJava言語デバッガがプロセスに接続することを許可する、接続コネクタが含まれています。これは、ハング・アップやデッドロックの発生時に各スレッドが何をしていたのかを示すのに役立つ可能性があります。「jdbユーティリティ」を参照してください。

jinfoユーティリティ

このユーティリティはJavaプロセスから構成情報を取得できます。「jinfoユーティリティ」を参照してください。

jmapユーティリティ

このユーティリティは、Javaプロセスからヒープ・ヒストグラムなどのメモリー・マップ情報を取得できます。Oracle SolarisおよびLinuxオペレーティング・システムでは、プロセスがハングアップした場合に-Fオプションを使用できます。「jmapユーティリティ」を参照してください。

jsadebugdデーモン

(Oracle SolarisおよびLinuxオペレーティング・システムのみ)

Serviceability Agent Debug Daemon (jsadebugd)は、Javaプロセスまたはコア・ファイルに接続し、デバッグ・サーバーとして動作します。「jsadebugdデーモン」を参照してください。

jstackユーティリティ

このユーティリティは、JavaプロセスからJavaおよびネイティブ・スタックの情報を取得できます。「jstackユーティリティ」を参照してください。

ネイティブ・ツール

各オペレーティング・システムには、ハング・アップやデッドロックの状況で役立つ可能性のあるネイティブ・ツールおよびユーティリティがあります。「オペレーティング・システムのネイティブ・ツール」を参照してください。

モニタリング・ツール

実行中のアプリケーションをモニターして問題を検知するためのツールおよびオプションのリスト。

表2-4に示すツールは、実行中のアプリケーションのモニター用に設計されています。

JVMおよびJavaアプリケーションに関する問題を診断するには、Java Mission Control、Java Flight Recorderおよびjcmdユーティリティを使用できます。診断機能を強化し、パフォーマンスのオーバーヘッドを削減するには、以前のjstack,、jinfoおよびjmapユーティリティのかわりに最新の診断ツールjcmdの使用をお薦めします。

表2-4 モニタリング・ツール

ツールまたはオプション 説明および使用方法

Java Mission Control

Java Mission Control (JMC)は、HotSpot JVM用の新しいJDKプロファイリングおよび診断ツール・プラットフォームです。基本的なモニタリングと管理、および本番稼働時のプロファイリングと診断を行う高性能なツール・スイートです。Java Mission Controlは、プロファイリング・ツールにつきもののパフォーマンス・オーバーヘッドの問題を最小限に抑えます。

jcmdユーティリティ

このユーティリティを使用してJVMに診断コマンド・リクエストを送信し、JVMではこれらのリクエストを使用してJavaフライト記録を制御します。JFRは、フライト記録のイベントを使用してJVMおよびJavaアプリケーションのトラブルシューティングと診断に使用されます。「jcmdユーティリティ」を参照してください。

JConsoleユーティリティ

このユーティリティは、Java Management Extensions (JMX)に基づくモニタリング・ツールです。このツールは、Java仮想マシンの組込みJMXインストゥルメンテーションを使用して、実行中のアプリケーションのパフォーマンスやリソース消費に関する情報を提供します。「JConsole」を参照してください。

jmapユーティリティ

このユーティリティは、Javaプロセス、コア・ファイル、またはリモート・デバッグ・サーバーから、ヒープ・ヒストグラムなどのメモリー・マップ情報を取得できます。「jmapユーティリティ」を参照してください。

jpsユーティリティ

このユーティリティは、ターゲット・システム上で計測されたJava HotSpot VMを一覧表示します。VMが埋め込まれた環境、つまりjava起動ツールではなくJNI呼び出しAPIを使ってVMが起動される環境では、このユーティリティが非常に役立ちます。「jpsユーティリティ」を参照してください。

jstackユーティリティ

このユーティリティは、JavaプロセスからJavaおよびネイティブ・スタックの情報を取得できます。Oracle SolarisおよびLinuxオペレーティング・システムでは、コア・ファイルまたはリモート・デバッグ・サーバーからも情報を取得できます。「jstackユーティリティ」を参照してください。

jstatユーティリティ

このユーティリティは、Javaの組込みインストゥルメンテーションを使用して、実行中アプリケーションのパフォーマンスやリソース消費に関する情報を提供します。このツールは、パフォーマンスの問題、特にヒープ・サイズ決定やガベージ・コレクションに関係する問題を診断するときに使用できます。「jstatユーティリティ」を参照してください。

jstatdデーモン

このユーティリティは、計測されたJava仮想マシンの作成と終了をモニターし、ローカル・ホスト上で実行されているVMにリモート・モニタリング・ツールが接続することを許可するインタフェースを提供する、Remote Method Invocation (RMI)サーバー・アプリケーションです。「jstatdデーモン」を参照してください。

visualgcユーティリティ

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

ネイティブ・ツール

各オペレーティング・システムには、モニタリング目的に役立つ可能性のあるネイティブ・ツールおよびユーティリティがあります。たとえば、Oracle Solaris 10オペレーティング・システムで導入された動的トレース(DTrace)機能は、高度なモニタリングを実行します。「オペレーティング・システムのネイティブ・ツール」を参照してください。

その他のツール、オプション、変数、およびプロパティ

問題の診断に役立つ一般的なトラブルシューティングのツール、オプション、変数およびプロパティのリスト。

特定タイプの問題向けに設計されたツールに加え、表2-5に示すツール、オプション、変数、およびプロパティは、その他の問題を診断するのに役立ちます。

JVMおよびJavaアプリケーションに関する問題を診断するには、Java Mission Control、Java Flight Recorderおよびjcmdユーティリティを使用できます。診断機能を強化し、パフォーマンスのオーバーヘッドを削減するには、以前のjstack,、jinfoおよびjmapユーティリティのかわりに最新の診断ツールjcmdの使用をお薦めします。

表2-5 一般的なトラブルシューティング・ツールおよびオプション

ツールまたはオプション 説明および使用方法

Java Mission Control

Java Mission Control (JMC)は、HotSpot JVM用の新しいJDKプロファイリングおよび診断ツール・プラットフォームです。基本的なモニタリングと管理、および本番稼働時のプロファイリングと診断を行う高性能なツール・スイートです。Java Mission Controlは、プロファイリング・ツールにつきもののパフォーマンス・オーバーヘッドの問題を最小限に抑えます。「Java Mission Control」を参照してください。

jcmdユーティリティ

このユーティリティを使用してJVMに診断コマンド・リクエストを送信し、JVMではこれらのリクエストを使用してJavaフライト記録(JFR)を制御します。JFRは、フライト記録のイベントを使用してJVMおよびJavaアプリケーションのトラブルシューティングと診断に使用されます。

jinfoユーティリティ

このユーティリティは、指定されたJavaプロセスの特定のJVMフラグの値を動的に設定、設定解除および変更できます。Oracle SolarisおよびLinuxオペレーティング・システムでは、構成情報も出力できます。

jrunscriptユーティリティ

このユーティリティはコマンド行スクリプト・シェルで、インタラクティブおよびバッチ・モードの両方のスクリプト実行をサポートしています。

Oracle Solaris Studio dbxデバッガ

これはインタラクティブなコマンド行デバッグ・ツールで、プログラムを停止してその状態を調べるなど、プログラムの動的実行を完全に制御できます。詳細は、Oracle Solaris Studioプログラム・デバッギングにあるdbxの最新ドキュメントを参照してください。

Oracle Solaris Studioパフォーマンス・アナライザ

このツールを使って、コードのパフォーマンスを評価し、潜在的なパフォーマンス問題を特定し、コード内で問題が発生する部分を突きとめることが容易になる可能性があります。Performance Analyzerはコマンド行、またはグラフィカル・ユーザー・インタフェースから使用できます。詳細は、Oracle Solaris Studioパフォーマンス・アナライザを参照してください。

Sunのデータ領域プロファイリング: DProfile

このツールは、Sunコンピューティング・システム内でのデータ・フローを洞察することで、ソフトウェアとハードウェアの両方のボトルネックを特定するのを支援します。DProfileは、Sun Studio 11コンパイラ・スイートでPerformance Analyzer GUI経由でサポートされています。DTraceまたは動的トレース診断ツールに関する項を参照してください。

-Xcheck:jniオプション

このオプションは、Java Native Interface (JNI)を使用する、またはサード・パーティのライブラリ(一部のJDBCドライバなど)を採用するアプリケーションの問題を診断する際に役立ちます。「-Xcheck:jniオプション」を参照してください。

-verbose:classオプション

このオプションは、クラスのロードとアンロードのロギングを有効にします。「-verbose:classオプション」を参照してください。

-verbose:gcオプション

このオプションは、ガベージ・コレクション情報のロギングを有効にします。「-verbose:gcオプション」を参照してください。

-verbose:jniオプション

このオプションは、JNIのロギングを有効にします。「-verbose:jniオプション」を参照してください。

JAVA_TOOL_OPTIONS環境変数

この環境変数では、ツールの初期化(具体的には-agentlibまたは-javaagentオプションを使用したネイティブまたはJavaプログラミング言語エージェントの起動)を指定できます。「環境変数とシステム・プロパティ」を参照してください。

java.security.debugシステム・プロパティ

このシステム・プロパティは、JavaのJREのセキュリティ・チェックが実行中にトレース・メッセージを出力するかどうかを制御します。「java.security.debugシステム・プロパティ」を参照してください。

java.lang.managementパッケージ

java.lang.managementパッケージは、JVMやオペレーティング・システムをモニターおよび管理するための管理インタフェースを提供します。

具体的には、次の各システムのインタフェースがカバーされています。

  • クラスのロード

  • コンパイル

  • ガベージ・コレクション

  • メモリー・マネージャ

  • ランタイム

  • スレッド

JDKには、java.lang.managementパッケージの使用方法を示すコード例が含まれています。これらの例は$JAVA_HOME/demo/managemenディレクトリにあります。コード例の一部を次に示します。

  • MemoryMonitorは、java.lang.management APIを使ってアプリケーションで消費されるすべてのメモリー・プールのメモリー使用量をモニターする方法を示します。

  • FullThreadDumpは、java.lang.management APIを使って完全なスレッド・ダンプを取得し、プログラムでデッドロックを検出する方法を示します。

  • VerboseGCは、java.lang.management APIを使ってアプリケーションのガベージ・コレクション統計やメモリー使用量を出力する方法を示します。

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

java.lang.instrumentパッケージ

java.lang.instrumentパッケージは、Javaプログラミング言語エージェントがJVMで実行中のプログラムを計測することを許可するサービスを提供します。

インストゥルメンテーションは、プロファイラなどのツールや、メソッド呼出しをトレースするためのツールなどで使用されます。このパッケージを使えば、ロード時および動的計測の両方が容易になります。また、ロード済クラスに関する情報や特定のオブジェクトが消費するストレージ量に関する情報を取得するメソッドも含まれています。

java.lang.Threadクラス

java.lang.Threadクラスには、すべてのライブ・メソッドのスタック・トレースのマップを返す、getAllStackTracesと呼ばれるstaticメソッドが含まれています。

Threadクラスには、スレッドの状態を返す、getStateと呼ばれるメソッドも含まれています。スレッドの状態はjava.lang.Thread.State列挙型で定義されます。これらのメソッドは、診断またはモニタリング機能をアプリケーションに追加する際に役立つことがあります。

JVM Tool Interface

JVM Tools Interface (JVM TI)とは、様々な開発ツールやモニタリング・ツールで使用できるネイティブ(C/C++)プログラミング・インタフェースです。

JVM TIは、VMの状態にアクセスする必要のある各種ツール(プロファイリング・ツール、デバッグ・ツール、モニタリング・ツール、スレッド分析ツール、カバレージ分析ツールを含むがこれに限らない)のためのインタフェースを提供します。

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

  • Java Debug Wire Protocol (JDWP)

  • java.lang.instrumentパッケージ

JVM TIの仕様は、JVM Tool Interfaceのドキュメントで参照できます。

JDKには、JVM TIの使用方法を示すコード例が含まれています。これらの例は$JAVA_HOME/demo/jvmtiディレクトリにあります。コード例の一部を次に示します。

  • mtraceは、メソッドの呼出しおよび復帰回数を追跡するエージェント・ライブラリです。これは、バイトコード・インストゥルメンテーションを使って仮想マシンにロードされたすべてのクラスを計測し、使用頻度の高いメソッドのソート済みリストを出力します。

  • heapTrackerは、オブジェクトの割当てを追跡するエージェント・ライブラリです。これは、バイトコード・インストゥルメンテーションを使ってコンストラクタ・メソッドを計測します。

  • heapViewerは、Ctrl+Breakハンドラが呼び出されたときにヒープ統計を出力するエージェント・ライブラリです。「Ctrl+Breakハンドラ」を参照してください。ロードされたクラスごとに、そのクラスのインスタンス数と使用済容量を出力します。

jrunscriptユーティリティ

jrunscriptユーティリティはコマンド行スクリプト・シェルです。

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

jrunscriptユーティリティは、Java言語とスクリプト言語との通信によって探求的なプログラミング・スタイルをサポートしています。

jsadebugdデーモン

Javaサービスアビリティ・エージェント・デバッグ・デーモン(jsadebugd)は、Javaプロセスまたはコア・ファイルに接続し、デバッグ・サーバーとして動作します。

このユーティリティは現在のところ、Oracle SolarisおよびLinuxオペレーティング・システムでのみ利用できます。jstackjmapおよびjinfoなどのリモート・クライアントは、Java Remote Method Invocation (RMI)を使用しているサーバーに接続できます。

jstatdデーモン

jstatdデーモンは、計測された各Java HotSpotの作成と終了をモニターし、ローカル・ホスト上で実行されているJVMにリモート・モニタリング・ツールが接続できるようにするインタフェースを提供する、RMIサーバー・アプリケーションです。

たとえば、このデーモンを使えば、jpsユーティリティでリモート・システム上のプロセスを一覧表示できます。

注意:

FAT32ファイル・システム上では、インストゥルメンテーションにアクセスできません。

スレッド・ダンプのスレッド状態

スレッド・ダンプに表示される可能性があるスレッド状態のリスト。

表2-6は、Ctrl+Breakハンドラによるスレッド・ダンプで可能なスレッド状態を示しています。

表2-6 スレッド・ダンプのスレッド状態

スレッド状態 説明

NEW

スレッドはまだ開始されていません。

RUNNABLE

スレッドはJVM内で実行されています。

BLOCKED

スレッドはモニター・ロックを待機してブロックされています。

WAITING

スレッドは、別のスレッドが特定のアクションを実行するのを無期限に待機しています。

TIMED_WAITING

スレッドは指定された待機時間、別のスレッドがアクションを実行するのを待機しています。

TERMINATED

スレッドは終了しています。

オペレーティング・システムに基づくトラブルシューティング・ツール

問題のトラブルシューティングに利用できるWindowsのネイティブ・ツールのリスト。

表2-7は、Windowsオペレーティング・システムで使用可能なトラブルシューティング・ツールの一覧を示しています。

表2-7 Windowsのネイティブ・トラブルシューティング・ツール

ツール 説明

dumpchk

メモリー・ダンプ・ファイルが正常に作成されたことを確認するコマンド行ユーティリティ。このツールは、MicrosoftのWebサイトから入手可能なDebugging Tools for Windowsダウンロードに含まれています。「Windowsでのクラッシュ・ダンプの収集」を参照してください。

msdevデバッガ

Visual C++およびWin32デバッガの起動に使用可能なコマンド行ユーティリティ。

userdump

User Mode Process Dumperは、MicrosoftのWebサイトから入手可能なOEM Support Toolsダウンロードに含まれています。「Windowsでのクラッシュ・ダンプの収集」を参照してください。

windbg

Windowsデバッガは、Windowsアプリケーションまたはクラッシュ・ダンプのデバッグに使用できます。このツールは、MicrosoftのWebサイトから入手可能なDebugging Tools for Windowsダウンロードに含まれています。「Windowsでのクラッシュ・ダンプの収集」を参照してください。

/Mdおよび/Mddコンパイラ・オプション

メモリー割当てを追跡するための追加サポートを自動的に含めるコンパイラ・オプション。

表2-8では、Linuxオペレーティング・システム・バージョン10で導入または改善されたいくつかのトラブルシューティング・ツールについて説明しています。

表2-8 Linuxのネイティブ・トラブルシューティング・ツール

ツール 説明

c++filt

C++分解シンボル名を分解解除します。このユーティリティは、Linux上のgccというネイティブC++コンパイラ・スイートとともに配布されます。

gdb

GNUデバッガ

libnjamd

メモリー割当ての追跡

lsstack

スレッド・スタックを出力します(Oracle Solarisオペレーティング・システムのpstackに類似)

すべてのディストリビューションがデフォルトでこのツールを提供しているわけではありません。したがって、オープン・ソース・ダウンロードからのダウンロードが必要になる場合があります。

ltrace

ライブラリ呼出しトレーサ(Oracle Solarisオペレーティング・システムのtruss -uと同等)

すべてのディストリビューションがデフォルトでこのツールを提供しているわけではありません。したがって、オープン・ソース・ダウンロードからのダウンロードが必要になる場合があります。

mtraceおよびmuntrace

GNU mallocトレーサ

pmappstackなどのprocツール

Oracle Solarisオペレーティング・システムのprocツールの一部(すべてではない)にはLinuxと同等のツールが含まれています。Linuxでのコア・ファイルのサポートはOracle Solarisオペレーティング・システムには及ばず、たとえば、pstackをコア・ダンプには使用できません。

strace

システム・コール・トレーサ(Oracle Solarisオペレーティング・システムのtruss -tと同等)

top

CPU負荷が非常に高いプロセスを表示します。

vmstat

プロセス、メモリー、ページング、ブロックI/O、トラップ、およびCPUアクティビティに関する情報を報告します。

表2-9は、Oracle Solarisオペレーティング・システムで使用可能なトラブルシューティング・ツールの一覧を示しています。

表2-9 Oracle Solarisオペレーティング・システムのネイティブ・トラブルシューティング・ツール

ツール 説明

coreadm

JVMによって生成されるコア・ファイルの名前と場所を指定します。

cpustat

CPUパフォーマンス・カウンタを使ってシステム動作をモニターします。

cputrack

CPUパフォーマンス・カウンタを使用してプロセスとLWPの動作をモニターします。

c++filt

C++分解シンボル名を分解解除します。このユーティリティは、Oracle Solarisオペレーティング・システム上のSUNWsproというネイティブC++コンパイラ・スイートとともに配布されます。

dtrace

DTraceは、Oracle Solaris 10オペレーティング・システムで導入された、動的トレース・コンパイラおよびトレース・ユーティリティです。これは、カーネル関数、システム・コール、およびユーザー関数の動的トレースを実行できます。このツールを使えば、入口、出口、およびその他のプローブ・ポイントで任意の安全なスクリプトを実行できます。スクリプトは、Dプログラミング言語と呼ばれる、Cに似ているが安全なポインタ・セマンティクス言語で記述されます。「DTraceツール」も参照してください。

gcore

プロセスのコア・ダンプを強制します。コア・ダンプの書込み後、プロセスは継続します。

intrstat

割込みスレッドで消費されるCPUに関する統計を報告します。

iostat

I/O統計を報告します。

libumem

このライブラリは、Oracle Solaris 9オペレーティング・システムupdate 3で導入され、高速かつスケーラブルなオブジェクト・キャッシュ用メモリー割当ておよび拡張デバッグ・サポートを提供します。このツールでは、メモリー管理のバグを検出して修正できます。「libumemツールによるリークの検出」を参照してください。

mdb

カーネルおよびユーザー・アプリケーションとクラッシュ・ダンプ用のモジュラ・デバッガ

netstat

各種ネットワーク関連データ構造体の内容を表示します。

pargs

プロセス引数、環境変数または補助ベクトルを出力します。ほかのコマンド(psなど)のように、長い出力が切り詰められることはありません。

pfiles

プロセス・ファイル記述子に関する情報を出力します。Oracle Solaris 10オペレーティング・システム以降、ファイル名も出力されるようになりました。

pldd

プロセスによってロードされた共有オブジェクトを出力します。

pmap

プロセスまたはコア・ファイルのメモリー・レイアウト(ヒープ、データおよびテキスト・セクションを含む)を出力します。Oracle Solaris 10以降は、スタック・セグメントがテキスト[stack]とスレッドIDで明確に識別されます。「pmapユーティリティの改善」を参照してください。

prstat

アクティブなOracle Solarisオペレーティング・システム・プロセスの統計を報告します。(topに類似)

prun

プロセスを実行モードに設定します(pstopの逆)。

ps

すべてのプロセスを一覧表示します。

psig

プロセスのシグナル・ハンドラを一覧表示します。

pstack

特定のプロセスまたはコア・ファイルのスレッドのスタックを出力します。Oracle Solaris 10オペレーティング・システム以降は、JavaフレームでJavaメソッド名を出力できます。「pstackユーティリティの改善」を参照してください。

pstop

プロセスを停止(中断)します。

ptree

指定されたPIDを含むプロセス・ツリーを出力します。

sar

システム・アクティビティ・レポータ

sdtprocess

CPU負荷が非常に高いプロセスを表示します(topに類似)。

sdtperfmeter

システム・パフォーマンス(CPU、ディスク、ネットワークなど)を示すグラフを表示します。

top

CPU負荷が非常に高いプロセスを表示します。このツールは、Oracle Solarisオペレーティング・システムではフリーウェアとして利用可能ですが、デフォルトではインストールされません。

trapstat

実行時トラップ統計(SPARCのみ)を表示します。

truss

システム・コール、ユーザー・モード関数、およびシグナルの入口および出口イベントをトレースし、オプションでこれらのイベントのいずれかでプロセスを停止します。このツールは、システム・コールやユーザー関数の引数も出力します。

vmstat

システム仮想メモリーの統計を報告します。

watchmalloc

メモリー割当てを追跡します。