診断ガイド

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

Oracle JRockit Mission Control の使用事例

この章では、Oracle JRockit Mission Control を使用して Oracle JRockit JVM 上で実行されるアプリケーションをモニタおよび管理できる、さまざまな方法を例示しています。以下の使用事例を説明します。

 


JRockit Management Console によるシステム動作の分析

Marcus は、JRockit JVM インスタンス上で実行している DemoLeak というアプリケーションをモニタして、最大限のパフォーマンスが得られるようにチューニングされているかどうかを確認したいと思っています。それを行うには、アプリケーションの実行と同時に、JRockit Management Console を実行します。Management Console は、メモリ、CPU 使用状況、その他の実行時メトリックに関する情報をリアルタイムに提供します。Management Console はマルチタブ インタフェースで、各タブによって、実行中のアプリケーションのモニタや、ある局面の管理を行うことができます。お使いのバージョンの Management Console で使用されるタブは、コンソールと一緒にインストールした Java プラグインによって変わります。完全に実装すると、コンソールには 8 つのタブと 1 つのメニューが表示され、7 つのプラグインにマップされます。

はじめに

まずマルクスは、次のように入力してコマンド プロンプトから JRockit Mission Control Client を起動します。

jrockit\bin\jrmc

JRockit Mission Control Client が起動している間に、DemoLeak アプリケーションを起動します。コマンド プロンプトには、次のように入力します。

jrockit\bin\java DemoLeak

次に、ローカル接続で Management Console を起動します。

Management Console を起動するには、次の手順を実行します。

  1. JRockit ブラウザで、接続対象とする JRockit JVM インスタンスを見つけます。この場合は DemoLeak クラスを実行している、[見つかったフォルダ|ローカル] の下のものです。
  2. 図 23-1 該当する JRockit JVM インスタンスを見つける


    該当する JRockit JVM インスタンスを見つける

  3. マウスを右クリックして、その接続のコンテキスト メニューを開きます。
  4. 図 23-2 選択した JRockit JVM インスタンスのコンテキスト メニュー


    選択した JRockit JVM インスタンスのコンテキスト メニュー

  5. Start Console を選択します。
  6. しばらくして、JRockit Mission Control Client の右パネルに Management Console が表示されます。JRockit Mission Control Client の Marcus の実装に以下のタブが表示されることに注意します。

    • [概要]
    • [MBean ブラウザ]
    • [メモリ]
    • [スレッド]
    • [ランタイム]
    • [トリガ]
    • [例外カウント]
    • [メソッド プロファイラ]

メモリ使用状況の分析

アプリケーション パフォーマンス上の問題を発見する方法の 1 つは、実行時のメモリの使用状況を確認することです。使用可能なメモリをアプリケーションがどのように使っているかを分析するには、[メモリ] タブを使用します。このタブでは、ヒープ使用状況、メモリ使用状況、およびガベージ コレクション方式に焦点を当てています。このタブに表示される情報は、最大限のアプリケーション パフォーマンスを引き出すように JRockit JVM をコンフィグレーションできているかどうかの判断に、非常に役立ちます。

メモリ使用状況を分析するには、次の手順を実行します。

  1. まず、[ヒープ] グラフを調べます。このグラフには、徐々に増えていく Java ヒープ使用量が示されます。やがてこれが使用可能なヒープのうち 80% から 90% に達すると、ガベージ コレクションがトリガされます。その時点で、グラフの表示値が再び少なくなり、新しいヒープ領域が使用できるようになったことが示されます。図  に示すように、このサイクルは、実行中は最初から最後まで繰り返されます。
  2. 図 23-3 [ヒープ] グラフ
  3. 次に、[メモリの統計] および [ガベージ コレクタ] パネルに目を向けます。これらはそれぞれ、メモリ使用状況とガベージ コレクタについての、さらなる情報を表示します。必要に応じて、このタブの値を変更することができます。たとえば、現在の Java ヒープ サイズの割り当てやガベージ コレクション方式では、最適なアプリケーション実行ができないと感じた場合には、これらを変更するとよいでしょう。

ガベージ コレクションの実行時間をプロットする

次に、ガベージ コレクションごとの期間を確認することにします。よくあることですが、ガベージ コレクションの実行時間が長すぎると、アプリケーションの パフォーマンスが低下します。ガベージ コレクションの期間を確認するために、この情報を [ヒープ] グラフ上でプロットすることができます。

各種タブに表示されるグラフはすべて、いくつかの有用なデフォルト属性を使用してあらかじめコンフィグレーションされていますが、任意の MBean からの任意の数値属性を追加可能です。J2SE 5.0 の標準的な MBean と JRockit JVM 固有の MBean に加えて、JRockit Mission Control 自体にも、他の複数の属性から属性を派生させる、いわゆる合成 MBean が用意されています。そのような属性の 1 つが、ガベージ コレクションの実行時間です。

注意 : ガベージ コレクション期間の属性は PauseTimes という名前ですが、Java アプリケーションは、ガベージ コレクションの全期間を通して停止し続ける必要はありません。コンカレント ガベージ コレクタを使用している場合、ガベージ コレクタは、ガベージ コレクションの期間のほとんどの間、Java アプリケーションと並行して処理を行います。この属性の名前が誤解を招きやすいことは確認済みの問題であり、将来のリリースで修正される予定です。修正後の属性名は Duration となる予定です。

そのためには、以下の手順を実行します。

  1. [メモリ] タブで [追加...] ([ヒープ] グラフの右側) をクリックします。
  2. [属性セレクタ] が表示されます。

  3. 図 23-4 に示すように PauseTimes 属性に到達するまでツリーを展開し、これを選択して [OK] をクリックします。
  4. 図 23-4 属性の選択と [ヒープ] グラフへの追加


    属性の選択と [ヒープ] グラフへの追加

    これで、新しい属性が [ヒープ] グラフに表示されるようになります。この合成属性のいくらか特殊な点は、ガベージ コレクションの実行時間の前後においてのみ値を示すということです。そのため、プロットは図 23-5 に示すように、三角形になります。値はミリ秒で表示されます。

    図 23-5 休止時間プロットが追加された [ヒープ] グラフ


    休止時間プロットが追加された [ヒープ] グラフ

警告トリガを設定する

システムのボトルネックを検出しようとして CPU の負荷のグラフを調べているときに、JVM の CPU 負荷が最大限に達していることに気付きました。より長い期間にわたって調べた場合、この現象がどの程度の頻度で発生するかを確認したいとします。CPU グラフを長時間観察し続ける代わりに、VM によって生成される CPU の負荷が高くなったときに警告トリガが通知されるように設定します。

警告を設定するには、次の手順を実行します。

  1. [トリガ] タブに移動して [追加...] ([トリガ ルール] の下) をクリックします。
  2. [新しいトリガ ルールの追加] ウィザードが表示されます。

  3. ツリーを展開し、図 23-6 に示すように VMGeneratedCPULoad を選択します。次に [Next] をクリックします。
  4. 図 23-6 トリガ対象となる属性の選択


     トリガ対象となる属性の選択

  5. 図 23-7 に示すように、条件を入力します。
  6. 図 23-7 トリガ条件の設定


    トリガ条件の設定

    CPU の負荷の値の範囲は 0 ~ -1 であるため、[最大トリガ値] に 0.95 を指定します。5 分間隔で CPU の使用状況が最大に達したときに警告を発生させるため、[持続時間 [秒]] に 300 を指定します。また、10 秒未満の間隔でのトリガ発生を回避するため、[限界時間 [秒]] を 10 に設定します。

  7. 次に [Next] をクリックします。
  8. [新しいトリガ ルールの追加 : アクションの選択] ダイアログ ボックスが表示されます (図 23-8)。[アプリケーション警告] を選択して、[Next] をクリックします。
  9. 図 23-8 トリガ アクションの選択


     トリガ アクションの選択

  10. [Next] をクリックして、トリガをいつ発動させるかについての制約 (省略可能) をスキップします。
  11. 図 23-9 に示すように、ルール名を指定し (CPU load for JRockit > 0.95)、[Finish] をクリックします。
  12. 図 23-9 ルール名の指定


    ルール名の指定

  13. その後、新しいルール名の横にあるボックスをチェックして、これをアクティブ化します。
  14. 図 23-10 選択済みのトリガ


    選択済みのトリガ

  15. 次に、有用なデータが取得されていることを確認するため、[メモリ] タブに戻り、CPU のアクティビティをチェックします。すると、[トリガ警告] ダイアログ ボックスが表示されないことに気付きました。そこで、[トリガ] タブに戻ってルールを選択し、[トリガ条件] の下の [最大トリガ値] を 0.90 程度まで下げ、ルールを編集します。
  16. イベントがトリガされるたびに [トリガ警告] ダイアログ ボックスが表示されることは避けたいので、[警告時にダイアログを表示] のチェックは外しておきます (このダイアログは必要に応じて [ウィンドウ] メニューから表示することができます)。

Console を使用してオンラインでメソッドのプロファイリングを行う

次にマルクスは、ある特定のメソッドが実行されている回数と期間を確認することにしました。これは、メソッド プロファイリングと呼ばれるプロセスです。JRockit Mission Control には、メソッドをプロファイリングするための 2 つのツールが用意されています。

[メソッド プロファイラ] タブを使用してメソッドをプロファイリングするには、次の手順を実行します。

  1. まず、メソッド プロファイリング テンプレートを作成する必要があります。そのためには、[メソッド プロファイラ] タブに移動して [テンプレート] パネルの [追加...] をクリックします。
  2. [テンプレートの追加] ダイアログ ボックスが表示されます。

  3. 図 23-11 に示すように、[テンプレートの追加] ダイアログ ボックスに新しいテンプレートの名前を入力します。
  4. 図 23-11 追加されたテンプレート名


    追加されたテンプレート名

  5. 次に [OK] をクリックします。
  6. ダイアログ ボックスが閉じ、新しいテンプレートがリストに追加されます (図 23-12)。

    図 23-12 追加された DemoLeak テンプレート


    追加された DemoLeak テンプレート

  7. テンプレート名の前にあるボックスをチェックして新しい DemoLeak テンプレートを有効化し、このテンプレートを選択して [DemoLeak] パネルの [追加...] をクリックします (図 23-13)。
  8. 図 23-13 [DemoLeak] パネル


    [DemoLeak] パネル

    [メソッド プロファイラへのクラスの追加] ダイアログ ボックスが表示されます。

  9. 図 23-14 に示すように、[メソッド プロファイラへのクラスの追加] ダイアログ ボックスで、java.util.Hashtable と入力します。
  10. 図 23-14 java.util.Hashtable クラスの追加


    java.util.Hashtable クラスの追加

  11. [OK] をクリックします。
  12. [DemoLeak] パネルで、java.util.Hashtable クラスを展開し、下にスクロールして put(Object, Object) メソッドおよび remove(Object) メソッドの前にあるボックスをチェックします (図 23-15 を参照)。
  13. 図 23-15 選択された java.util.Hashtable メソッド


    選択された java.util.Hashtable メソッド

  14. 次に、[コントロール パネル] にある緑色の開始ボタンをクリックして、プロファイリングを開始します (図 23-16)。
  15. 図 23-16 プロファイリング開始ボタン


    プロファイリング開始ボタン

  16. 結果を解釈するには、[プロファイリング情報] パネルを調べます。Hashtable.put(Object, Object) の呼び出し回数の増え方が、Hashtable.remove(Object) の呼び出し回数よりもわずかに速いことが分かりました。
  17. その後、[コントロール パネル] の赤い停止ボタンをクリックして、プロファイリングを停止します (図 23-17)。
  18. 図 23-17 プロファイリング停止ボタン


    プロファイリング停止ボタン

 


JRockit Runtime Analyzer によるシステム上の問題の分析

フィオナは、アプリケーション DemoLeak のパフォーマンスに不満を抱いています。特に、実行時間が長くなった場合のアプリケーションのパフォーマンス状況が気になります。たとえば、実行し始めて間もないときにはうまく機能しているのに、しばらくすると間違った結果を報告したり、不適切なところで例外を送出したりするようになるのです。また何度実行しても、最終的にはほぼ同じ時間でハングアップしてしまうことにも気付きました。何が問題なのかを見極めるため、フィオナは JRockit Runtime Analyzer (JRA) を使用して、実行時分析を作成することにします。

JRA は、オンデマンドの「フライト レコーダ」として、JVM および JVM が実行しているアプリケーションに関する詳細な記録を生成します。記録されたプロファイルは、後から JRA ツールを使ってオフラインで分析することができます。記録されるデータには、メソッドとロックのプロファイリングのほかに、ガベージ コレクションの統計、最適化の判断、レイテンシ分析 (JRockit Mission Control 3.0) などがあります。

はじめに

診断プロセスを開始するには、次の手順を実行します。

  1. 次のように入力して、コマンドラインから JRockit Mission Control Client を起動します。
  2. jrockit\bin\jrmc
  3. JRockit Mission Control Client が起動している間に、次のように入力して DemoLeak を起動します。
  4. jrockit\bin\java DemoLeak

記録の作成

次に、ローカル接続から JRA 記録を作成します。それには、次の手順を実行します。

  1. JRockit Mission Control Client を起動して JRockit ブラウザで、接続対象とする JRockit JVM インスタンスを見つけます。この場合は DemoLeak クラスを実行している、[見つかったフォルダ|ローカル] の下のものです。
  2. マウスを右クリックして、選択した接続のコンテキスト メニューを表示します。
  3. [JRA 記録を開始] を選択して、[JRA 記録の開始] ウィザードを起動します。
  4. 記録を開始したい JVM インスタンスへの接続を選択します。
  5. ファイル名とディレクトリを選択し、[ローカル ファイル名] フィールドに、記録に付ける分かりやすい名前を入力します。JRA 記録ファイルは、別のパスを指定しない限り、JVM プロセスのカレント ディレクトリに作成されます。古いファイルがすでに存在する場合は、新しい記録によって上書きされます。
  6. 必要な記録時間を秒単位で [記録時間] に入力します。
  7. 注意 : 設定した記録時間が短すぎる (たとえば 30 秒未満) 場合は、おそらく有意義な記録となるに足りるサンプル データは取得できません。
  8. 表 23-1 で説明するサンプリング オプションを選択します。
  9. 表 23-1 選択されるサンプリング オプション
    サンプリング オプション
    説明
    [メソッド サンプリングの有効化]
    メソッドのサンプルを記録
    [GC サンプリングの有効化]
    ガベージ コレクション イベントを記録
    [ネイティブ サンプリングの有効化]
    ネイティブ コードのサンプルを記録
    [サーバの記録の圧縮]
    記録を zip ファイルとして圧縮
    [Selected JRockits]
    記録を作成する JRockit JVM インスタンスを表示

  10. [開始] をクリックします。
  11. JRA 記録の進行状況ウィンドウが表示されます。記録が終了すると、JRA 内にその記録がロードされます。この後、JRA 記録を確認します。

記録の確認

次に、フィオナは JRockit Mission Control Client を使用して、JRA 記録を表示します。まず、[全般] タブを開いて、以下の手順を実行します。

  1. JRockit Mission Control Client で、[ファイル|ファイルを開く|JRA 記録を開く] をクリックします。
  2. 記録ファイルを見つけて選択し、[開く] をクリックします。
  3. [OK] をクリックします。
  4. その記録ファイルに関する JRA の [全般] タブが開いて、記録内のデータを確認できるようになります。[全般] タブには、JVM、システム、およびアプリケーションに関する情報が表示されます。このタブは表  23-2 で説明するパネルに分かれています。

    表 23-2 [全般] タブのセクション
    データ フィールド
    説明
    [概要]
    JVM、オペレーティング システム、記録時間などについて、すべての全般的な情報が含まれる。
    [メモリ使用量]
    JRockit JVM がどのようにメモリを使用しているかに関する情報が含まれる。
    [VM の引数]
    使用された起動オプションがすべてリストされる。
    [割り当て]
    アプリケーションが Java ヒープに対してどのようにメモリを割り当てているかに関する情報が含まれる。
    [スレッド]
    スレッドの使用に関する情報が含まれる。
    [例外]
    例外関連の情報が含まれる。

このタブを見ることで、フィオナは自分が JVM のどのバージョンを実行したのかを確認できます。また、大きいオブジェクトが 1 秒当たり 22.153 MB の割合または「頻度」で割り当てられている一方で、小さいオブジェクトはそれより大幅に高い 1 秒当たり 261.983 MB という頻度で割り当てられていることも分かります。

[メソッド] タブの確認

次に、[メソッド] タブを確認します。[メソッド] タブには、トップ ホット メソッドが記録中の祖先および子孫と共にリストされます。[メソッド] タブは、表 23-3 で説明する以下のパネルに分かれています。

表 23-3 [メソッド] タブのパネル
フィールド
説明
[トップ ホット メソッド]
トップ ホット メソッドのリスト。ホット メソッドは、アプリケーション実行中に JVM がほとんどの時間を費やすメソッドとして定義されている。特定のメソッドが「ホット」であるということは、そのメソッドがシステム上の問題の原因であることを示す場合がある。
[祖先]
[トップ ホット メソッド] リストで選択されたメソッドを呼び出す前に呼び出された、すべてのメソッドのリスト。この情報は、特定のメソッドのある局面が、システム パフォーマンス低下に加担しているかどうかの判断に役立つ可能性がある。選択したメソッドが多すぎた場合、このセクションには情報が表示されない。
[子孫]
[トップ ホット メソッド] リストで選択されたメソッドを呼び出した後に呼び出された、すべてのメソッドのリスト。この情報は、特定のメソッドのある局面が、システム パフォーマンス低下に加担しているかどうかの判断に役立つ可能性がある。選択したメソッドが多すぎた場合、このセクションには情報が表示されない。

トップ ホット メソッドを確認する

JRockit JVM におけるメソッド サンプリングは、CPU サンプリングに基づいています。図 23-18 に示すように、[トップ ホット メソッド] セクションには、記録中にサンプリングされたすべてのメソッドがリストされ、最も多くサンプリングされたメソッドから順にソートされます。

図 23-18 トップ ホット メソッド

[トップ ホット メソッド]

注意 : 記録の際にネイティブ サンプリングを有効化していた場合は、jvm.dll#_qBitSetClear のようにポンド記号 (#) が表示されます。この記号により、JVM 自身や、オペレーティング システムの各種ライブラリなど、ネイティブ ライブラリの関数であることが示されます。

トップ ホット メソッドのリストから、最もホットなメソッド 3 つは以下のとおりであることが分かります。

この情報がフィオナにとって、懸念の対象となり得る領域を探し始める際の、有効な手掛かりとなります。最もホットなメソッドとは、最も頻繁にサンプリングされるメソッドであることは分かっています。状況によっては、上位のホット メソッドに対するサンプリング数が、下位のメソッドのサンプリング数の成長を抑制することになります。ホット メソッドは、パフォーマンス上の問題、特にメモリ リークに関しては、有効な指標となります。なぜなら、サンプリング量が大きいと、JVM がその特定のメソッドを実行している時間の長さに影響が及ぶからです。

ガベージ コレクション イベントを確認する

次にフィオナは、実行時のシステム動作とガベージ コレクションのパフォーマンスをよりよく理解するため、[GC] タブ (図 23-19) を調べます。

図 23-19 [GC] タブ

[GC] タブ

このタブは、表 23-4 で説明する 6 つのパネルに分かれています。

表 23-4 [GC] イベント タブ パネル
パネル
説明
GC イベント概要タイムライン
このタイムラインは、記録が最初に開始された時点に基づき、記録全体を示す。フィオナはこの情報を、ヒープ使用量グラフの見直しの際に使用する。
ヒープ使用量グラフ
このグラフは、休止時間と比較してのヒープ使用量と、それが記録中にどのように変化するかを示す。GC イベント概要の中から特定の領域を選択すると、その部分の記録しか表示されなくなる。[ヒープ使用量] ドロップダウン リスト (図 23-19 の「6」) でグラフの内容を変更すると、それぞれの古いコレクション後の参照およびファイナライザのグラフ表示を得ることができる。
[ガベージ コレクション] イベント
このリストには、記録中に発生したすべてのガベージ コレクション イベントが示される。特定のイベントをクリックすると、ヒープ使用量グラフ内に、その特定のイベントのフラグが表示される。
[詳細]
このパネルには、特定の回のガベージ コレクションに関するすべての詳細情報が表示される。[ガベージ コレクション] リストから、あるガベージ コレクションを選択すると、古いコレクションと若いコレクションのどちらを選択したかに応じて、[詳細] セクションのタブが変化する。
チャートのコンフィグレーション
このパネルでは、アクティブなチャート上の表示方式を変えることができる。
[ヒープ使用量]
[ヒープ使用量] チャートの表示を、[参照とファイナライザ] 表示に切り替えるには、このリストを使用する。各コレクション後の、各種参照数が表示される。

[ガベージ コレクション] パネル (図 23-20) のデータを検証したフィオナは、ガベージ コレクションによる休止時間を長いものから 3 つ示すと、「95 (856 ms)」、「41 (707 ms)」、および「73 (691 ms)」であることを見て取りました。

図 23-20 [ガベージ コレクション] パネル

[ガベージ コレクション] パネル

このデータが示唆しているのは、アプリケーション上で処理が続行していくうちに、ガベージ コレクションにかかる時間が長くなっていったということです。これで、アプリケーション パフォーマンス劣化の原因と考えられる要素の診断に役立つ証拠が、さらに得られました。ガベージ コレクションの実行時間が、特に実行時の後になるほど増大していくことで、解放するヒープ領域が減っていることが分かります。以上のことからある程度の確信をもって、メモリ リークが発生していると予測できます。

注意 : この例では、フィオナはかなり早いうちにメモリ リークの発生を悟ります。これが判明するのは、はっきりとそれを指し示す証拠があるからです。大半の場合、メモリ リークが明らかになるのは、もっと後になってからで、おそらく [GC] タブで自明となることはないでしょう。ここで判明しない場合、ユーザは、「メモリ リークの検出」で説明する JRockit Memory Leak Detector の使用によって、さらに的確な結果を得られます。

[GC 全般] タブを確認する

[GC 全般] タブ (図 23-21) を確認することで、ガベージ コレクションのアクティビティがメモリ リークを示している可能性について、より深い理解を得ることができます。

図 23-21 [GC 全般] タブ

[GC 全般] タブ

このタブは、ガベージ コレクション情報を一目で見て取ることができる、3 つのパネルに分かれています。各パネルについては、表 23-5 で説明します。

表 23-5 [GC 全般] タブ
パネル
説明
[全般]
このセクションには、JRA 記録全体にわたってのガベージ コレクションに関する総合的な統計が表示される。
[ガベージ コレクション呼び出しツリー]
このセクションは、JRA 記録のすべてのガベージ コレクションについてサンプリングされた、すべての呼び出しトレースの集合である。
[GC 方式の変化]
このセクションには、ガベージ コレクション方式の変更が生じた時間と、それがどのように変化したかがリストされる。

スタック ツリーをユーザ コードまで展開したフィオナは、多くの割り当てが hashtable タイプからのものであることを見て取ります。これはつまり、このタイプについて、集中的に割り当てが行われているということです。このタイプの割り当てを減らすことにより、メモリ管理システムに対する負荷を削減できる可能性があります。

オブジェクト統計を比較する

次にフィオナは、記録開始時に収集されたオブジェクト統計を、記録後に収集されたオブジェクト統計と比較することが役立つだろうと判断しました。記録セッションの開始時と終了時には、Java ヒープを占めるオブジェクト タイプのうち最も一般的なタイプとクラス、すなわち、インスタンス数の合計がメモリ内に占める領域が最も大きいタイプの、スナップショットが取られます。結果は、[オブジェクト] タブに表示されます (図 23-22)。

図 23-22 [オブジェクト] タブ

[オブジェクト] タブ

[オブジェクト] 統計タブは、表 23-6 で説明する各パネルに分かれます。

ここでも、最も劇的な増加が見られるのは hashtable であり、これがヒープ上で最も多くのメモリ量を消費していることが分かります。これもまた、メモリ リークが発生していることだけでなく、このリークが hashtable オブジェクト内で生じているということを顕著に示しています。

ロック プロファイリング情報を確認する

フィオナは次に、ロックに関係のあるパフォーマンスのボトルネックの手がかりを見つけるために、ロック統計をチェックすることにしました。そこで、アプリケーションと特定の JRockit JVM インスタンスの双方について、この情報を調べるため、[ロック] タブ (図 23-23) を開きます。

図 23-23 [ロック] タブ

[ロック] タブ

ロック プロファイリング タブは、表 23-7 で定義する各パネルに分かれます。

表 23-7 ロック プロファイリング タブのパネル
パネル
説明
[Java ロック]
このセクションには、アプリケーション内のすべてのロックがリストされる。
[ネイティブ ロック]
このセクションには、JVM 内のすべてのロックがリストされる。

[Java ロック] パネルを見ると、非競合ロックは他のオブジェクトでは比較的少ないのに対して、hashtable タイプでは 3 億以上も取得されているということが、即座に分かります。この情報が直接、メモリ リークに結び付くわけではありませんが、低パフォーマンスであることを示してはいます。

ロックの大半は非競合であるため、hashmap のような非同期のデータ構造に切り替え、競合が発生する可能性がある少数のケースにのみ同期を使用することで、アプリケーションを最適化できます。

 


メモリ リークの検出

アプリケーションの実行状況が悪いのは、メモリ リークのせいであると判断したフィオナは、その疑惑を確信に変え、修正措置をとり始めるために、JRockit Memory Leak Detector の Memory Leak Detector を利用できます。メモリ リークは、不要になったメモリをプログラムが解放できずにいる場合に発生します。この用語は、実は名称としては正しくありません。なぜなら、メモリは物理的にコンピュータから失われているわけではないからです。実際には、あるプログラムにメモリが割り当てられ、その後、プログラム ロジックに不備があるために、そのプログラムがメモリにアクセスできなくなるのです。

はじめに

メモリ リーク検出プロセスを開始するには、次の手順を実行します。

注意 : この手順説明では、JRA 記録完了後に、アプリケーションが停止されたことが前提となっています。アプリケーションを停止していない場合、手順 1 および手順 2 は省略できます。
  1. コマンドラインに次のように入力して、アプリケーションを起動します。
  2. java DemoLeak
  3. アプリケーションが起動している間に、アプリケーションが実行されているサーバへの接続を作成します。
  4. 次に、以下の手順を実行して、Memory Leak Detector を起動します。
    1. JRockit ブラウザで Oracle JRockit JVM インスタンスを右クリックして、コンテキスト メニューを開きます。
    2. [memleak の開始] (図 23-24) を選択します。
    3. 図 23-24 コンテキスト メニューからの Memory Leak Detector の起動


      コンテキスト メニューからの Memory Leak Detector の起動

Java アプリケーションの分析

フィオナは、Memory Leak Detector の起動時に開く [傾向] タブ (図 23-25) の分析を開始しました。

図 23-25 [傾向] タブ

[傾向] タブ

ヒント : 傾向分析はデフォルトで実行されているはずです。実行されていない場合は、傾向分析ボタンの中にある開始ボタン (図 23-27) をクリックすることで起動できます。

傾向分析ページには、アプリケーションのオブジェクト タイプについて、メモリ使用量の傾向の統計値が表示されます。このデータは、ガベージ コレクションの最中に JVM によって収集されます。そのため、傾向が表示されるにはガベージ コレクションが少なくとも 2 回は実行されている必要があります。

図 23-26 ガベージ コレクション ボタン
[傾向] タブ
  1. 結果をより早く入手するために、フィオナはガベージ コレクション ボタン (図 23-26) を数回クリックして、ガベージ コレクションを複数回起動します。
  2. 図 23-27 傾向分析ボタン


    傾向分析ボタン

  3. 次に、傾向分析ボタンの中にある一時停止ボタン (図 23-27) をクリックして、傾向分析を休止します。
  4. 図 23-28 参照中のタイプを表示


    参照中のタイプを表示

DemoObject という名前のクラスの増大が最大であることが分かります。

  1. DemoObject クラスを右クリックし、図 23-28 に示すように、ドロップダウン メニューの [参照中のタイプを表示] を選択します。
  2. 図 23-29 [タイプ] タブ


    [タイプ] タブ

これにより、[タイプ] タブ (図 23-29) が開きます。DemoObject はハッシュテーブルのエントリに格納されていることが分かります。

  1. java.util.Hashtabe$Entry ノードの正符号 (+) をクリックして、ハッシュテーブルのエントリを参照中のタイプを表示するグラフを展開します。
  2. 増大傾向をまったく示していない灰色のノードが見つかるまで、グラフを左側に続けて展開していきます。

これで、DemoObject が確かにハッシュテーブルのエントリに格納されていることが分かります。次の手順は、これらの DemoObject を格納しているハッシュテーブル エントリを保持しているインスタンスについて詳しく調べることです。

図 23-30 インスタンスをリスト

インスタンスをリスト

  1. DemoObject を参照しているノードを右クリックし、図 23-30 に示すように、ドロップダウン メニューから [インスタンスをリスト] を選択します。
  2. 図 23-31 指し示すインスタンスを表示


    指し示すインスタンスを表示

アプリケーションのすべてのハッシュテーブル エントリが同じタイプのオブジェクトを指し示しているのではないため、表示する参照タイプを選択するためのポップアップが表示されます。

  1. 表示したいタイプは DemoObject であるため、ポップアップ (図 23-31) で、DemoObject を選択し [OK] をクリックします。
  2. 図 23-32 参照中のインスタンスを表示


    参照中のインスタンスを表示

[タイプ] タブの下部に、DemoObject を参照する java.util.Hashtable$Entry インスタンスのリストが表示されます。

  1. 一番上にあるインスタンスを右クリックして、[参照中のインスタンスを表示] (図 23-32) を選択し、このハッシュテーブル エントリを保持しているインスタンスの分析を開始します。
  2. 図  23-33 [インスタンス] タブ


    [インスタンス] タブ

これにより、図 23-33 に示す [インスタンス] タブが開きます。

  1. [タイプ] タブと同様に、正符号 (+) をクリックして、グラフを左側に展開します。

ハッシュテーブルに格納されている DemoObject は、DemoThread によって保持されていることが判明しました。これがメモリ リークの原因だと考えられます。

リーク検出

Oracle JRockit Mission Control ツールを使って収集した証拠から判断して、フィオナはシステムで生じている問題がメモリ リークであることを特定できただけでなく、どのオブジェクト タイプでメモリ リークが発生しているのかを正確に見つけることができました。特定を行うための最初の手掛かりとなったのは、JRA 記録を見てガベージ コレクションの期間が増大していることに気付き、それら長期化しているガベージ コレクションが発生しているタイプに注目したことでした。そしてその後 Memory Leak Detector を実行し、疑わしいタイプのうち実際にはどれがリーク源であるのかを突き止めました。彼女は、インスタンスと割り当て数が増加し続けていたタイプを見つけることができました。明らかに、これらがメモリを保持していたせいで、他のオブジェクトを割り当てるためにメモリを解放することができていませんでした。これが決め手となって、メモリ リークと、その発生場所が特定されました。


  ページの先頭       前  次