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

前
次

4 JFRを使用したパフォーマンスの問題のトラブルシューティング

この章では、Javaアプリケーションのパフォーマンスの問題を識別し、Javaフライト・レコーダを使用してこれらの問題をデバッグします。

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

JFRの商用ライセンスの詳細は、ライセンス契約を参照してください。フライト記録の作成の詳細は、「フライト記録の作成方法」を参照してください。

Javaフライト・レコーダは、パフォーマンスの問題を調査するための優れたツールです。パフォーマンス・オーバーヘッドによって結果をゆがめることなく、これほど多くのプロファイリング・データを提供するツールは他にありません。この章では、識別できるパフォーマンスの問題の例を示し、Javaフライト・レコーダを使用して問題をデバッグします。

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

JFRのオーバーヘッド

パフォーマンスを測定する場合は、フライト・レコーダ自体によって追加されるパフォーマンス・オーバーヘッドを考慮することが重要です。オーバーヘッドは、アプリケーションに応じて異なります。パフォーマンス・テストがセット・アップされている場合は、特定のアプリケーションに顕著なオーバーヘッドが存在するかどうかを測定できます。

ただし、デフォルトの設定を使用して標準のプロファイリング記録を記録するためのオーバーヘッドは、ほとんどのアプリケーションで2%未満です。通常、標準の連続記録の実行では、測定可能なパフォーマンスへの影響はありません。

オーバーヘッドの1つの大きな要因は、デフォルトで無効になっているヒープ統計イベントです。ヒープ統計を有効にすると、テスト実行の開始時と終了時にOldガベージ・コレクションがトリガーされます。これらのOld GCは、アプリケーションに追加の休止時間を与えるので、遅延を測定している場合または休止時間の影響を受けやすい環境では、ヒープ統計を有効にして実行しないでください。メモリー・リークをデバッグするとき、またはアプリケーションのライブ・セットを調査するとき、ヒープ統計は便利です。「Javaフライト・レコーダを使用したメモリー・リークのデバッグ」を参照してください。

注意:

パフォーマンスのプロファイリングのユース・ケースでは、この情報は必要でない場合があります。

ボトルネックの検出

ボトルネックは、アプリケーションごとに異なります。一部のアプリケーションにとって、ボトルネックは、I/Oまたはネットワークの待機、スレッド間の同期、または実際のCPU使用率である場合があります。また、ガベージ・コレクションの回数がボトルネックである場合もあります。複数のボトルネックを持つアプリケーションもあります。

アプリケーションのボトルネックを見つけるための1つの方法として、「イベント」タブを調べます。これは詳細設定タブであり、実行することがいくつかあります。まず、「イベント」タブをクリックし、JFRウィンドウの左側にある「イベント・タイプ」タブを開きます。ここは、調査するイベントを選択する場所です。現時点では、図4-1に示すように、統計情報割当てを除くすべてのJavaアプリケーションのイベントを選択します。

図4-1 ボトルネックの検出 - Javaアプリケーションのイベント

図4-1の説明が続きます
「図4-1 ボトルネックの検出 - Javaアプリケーションのイベント」の説明

これで、すべての「イベント」タブに、これらのイベントのみが表示されるようになります。次に、図4-2に示すように、「グラフ」タブからJavaアプリケーションのメイン・スレッドを見てください。

図4-2 ボトルネックの検出 - 「グラフ」タブのメイン・スレッド

図4-2の説明が続きます
「図4-2 ボトルネックの検出 - 「グラフ」タブのメイン・スレッド」の説明

「グラフ」タブは、最初は把握するのが困難かもしれません。各行はスレッドであり、各スレッドは複数の行を持つことができます。図4-2の各スレッドは、この記録のために「イベント・タイプ」タブで有効にされたJavaアプリケーションのイベントを表す行を持ちます。選択されたJavaアプリケーションのイベントはすべて、スレッド・ストール・イベントであるという重要なプロパティを持ちます。スレッド・ストールは、スレッドがイベント中にアプリケーションを実行していなかったことを示し、これらはすべて期間イベントです。期間イベントは、アプリケーションが実行されていなかった時間を測定します。

「イベント・タイプ」タブから、各イベントの色を見てください。たとえば、黄色は、Java Monitor Waitイベントを表します。黄色い部分は、スレッドがオブジェクトを待機しているときです。これは多くの場合、スレッドがタスクを待機して、アイドル状態であることを意味します。は、Java Monitor Blockedイベントまたは同期イベントを表します。Javaアプリケーションの重要なスレッドがブロックされた状態で多くの時間を費やしている場合は、アプリケーションの重要なセクションがシングル・スレッドであり、それがボトルネックであることを意味しています。は、ソケット読取りおよびソケット書込みイベントを表します。再び、Javaアプリケーションがソケットを待機している時間が多い場合、主なボトルネックは、ネットワーク内またはアプリケーションが通信する他のマシンにある可能性があります。

図4-2で、は、イベントがない部分を表します。の部分は、スレッドがスリープ中、待機中、ソケットの読取り中ではなく、ブロックもされていないことを意味します。通常、ここはアプリケーション・コードが実行される場所です。Javaアプリケーションの重要なスレッドがアプリケーション・イベントを生成せずに多くの時間を費やしている場合、アプリケーションのボトルネックは、コードの実行に費やした時間、またはCPU自体です。

注意:

ほとんどのJavaアプリケーション・イベント・タイプについて、20ミリ秒より長いイベントのみが記録されます。(このしきい値は、フライト記録を開始するときに変更できます。)要約すると、アプリケーションがファイルへの書込み(一度に一部分のみ)などの短いタスクを多数実行しているか、非常に短時間の同期に時間を費やしているので、領域には記録されたイベントがない可能性があります。

前述の各ボトルネックは、フライト記録内でさらに調査できます。

「イベント」タブには、ガベージ・コレクションが表示されず、ガベージ・コレクションがボトルネックになるかどうかを示しません。ガベージ・コレクションのパフォーマンスについて次のトピックを参照してください。

ガベージ・コレクションのパフォーマンス

Javaアプリケーションのガベージ・コレクションの問題は、JFRを使用して診断できます。

HotSpotガベージ・コレクタをチューニングすると、パフォーマンスに大きな影響を与える可能性があります。概要は、ガベージ・コレクション・チューニング・ガイドを参照してください。

まず、アプリケーションが起動し実行中であるとき、そのプロファイリング・フライト記録を取ります。ヒープ統計を含めると、追加のOldコレクションがトリガーされるので、ヒープ統計を含めないでください。よいサンプルを得るには、より長い記録を取ります(たとえば1時間)。

「メモリー」タブ、「GC回数」サブタブの順に選択します。「GC回数」は、GCの全体的なパフォーマンスへの影響を調査するために最適なタブです。右上の「すべてのコレクションの一時休止時間」セクションを参照し、記録からの「平均の一時休止合計」「最大の一時休止合計」および「合計一時休止時間」を見てください。「休止の合計」は、GC中にアプリケーションが一時休止した時間の合計です。多くのGCは、バックグラウンドでほとんどの処理を行います。この場合、GCの長さは重要ではなく、アプリケーションが実際に停止していた時間が重要です。したがって、「休止の合計は、GCの影響を適切に測定します。

図4-3は、5分間のフライト記録を示しています(時間選択バーに表示されたとおり)。この間の「平均の一時休止合計」は16ms、「最大の一時休止合計」は49ms、および「合計一時休止時間」は2s 86msでした。

図4-3 ガベージ・コレクションのパフォーマンス - GCの一時休止

図4-3の説明が続きます
「図4-3 ガベージ・コレクションのパフォーマンス - GCの一時休止」の説明

ガベージ・コレクションの主なパフォーマンスの問題は、通常、個々のGCの時間がかかりすぎるか、GCの一時休止(GCの一時休止の合計)に多くの時間を費やしているかのいずれかです。

個々のGCに時間がかかりすぎる場合は、GCの戦略を変更する必要があります。一時休止の回数とスループット・パフォーマンスの対比となると、各GCには異なるトレードオフがあります。動作ベースのチューニングに関する項を参照してください。

たとえば、ファイナライザまたは準参照の使用を減らすように、アプリケーションの修正が必要になる場合もあります。

アプリケーションが一時休止している時間が多すぎる場合は、様々な回避方法があります。

1つの方法は、Javaヒープ・サイズを増加することです。「ガベージ・コレクション」サブタブを見てアプリケーションが使用するヒープ・サイズを推定し、「Xms」および「Xmx」をより高い値に変更します。Javaヒープが大きいほど、GC間の時間は長くなります。Javaアプリケーションにメモリー・リークがあると、GCがますます頻繁になり、最後にはOutOfMemoryErrorがスローされる可能性があるので、注意が必要です。詳細は、「Javaフライト・レコーダによるメモリー・リークのデバッグ」を参照してください。

GCの数を減らすもう一つの方法は、より少ない一時オブジェクトを割り当てることです。「割当て」タブの下で、記録の過程で割り当てられているメモリ量を見てください。小さなオブジェクトは「TLAB」内に割り当てられ、大きなオブジェクトは「TLAB」外に割り当てられています。多くの場合、割当ての大半は「TLAB」内で起こります。

最後に、必要なGCを減らすために割当て率を減らします。「新しいTLABの割当て」タブ、「割当て」タブの順に選択して、メモリー不足が激しい割当てサイトおよびスタック・トレースを調べます。クラスごとにそれを表示するか、「スレッドによる割当て」を選択してほとんどの割当てを消費しているスレッドを確認できます。

JFRの「割当て」タブの一般的な詳細は、「フライト記録の検査」を参照してください。

これ以外のいくつかの設定により、JavaアプリケーションのGCのパフォーマンスが向上することもあります。GCパフォーマンスの詳細は、『Java Platform, Standard Edition HotSpot Virtual Machineガベージ・コレクション・チューニング・ガイド』のガベージ・コレクション・チューニング・ガイドに関する項を参照してください。

同期パフォーマンス

Javaアプリケーションの同期の問題をデバッグする場合、またはアプリケーションのスレッドがモニターに入るのを待機している時間が長い場合、「スレッド」タブ・グループの「競合」タブを見てください。

最も競合しているロック、およびロックの取得を待機しているスレッドのスタック・トレースに注目してください(図4-4を参照)。

図4-4 同期パフォーマンス - 「競合」タブ

図4-4の説明が続きます
「図4-4 同期パフォーマンス - 「競合」タブ」の説明

図4-4では、上部の範囲セレクタを使用してイベントが発生した場所を確認できます。選択した時間範囲内の競合イベントの範囲セレクタを拡大してください。

通常、問題になると予想されていなかった競合を探します。ロギングは、一部のアプリケーションで予想外のボトルネックになる可能性がある共通領域です。

プログラムの更新後またはいずれかの特定の時間に、Javaアプリケーションのパフォーマンスの低下が見られる場合は、状況がよいときにフライト記録を取り、状況が悪いときに別のフライト記録を取って、大きく増加している同期サイトを探します。

注意:

範囲セレクタに表示されるイベントは、すべてが同期イベントとはかぎりません。デフォルトでは、期間が20ミリ秒より長い競合イベントが記録されます。(このしきい値は、フライト記録を開始するときに変更できます。)より短いしきい値は、より多くのイベントを与えますが、オーバーヘッドが増加する可能性があります。競合が問題であると考えている場合は、非常に低いしきい値(ほんの数ミリ秒)で短い記録を取ることができます。これをライブ・アプリケーションで実行する場合は、非常に短い記録から開始し、パフォーマンス・オーバーヘッドを監視してください。

I/Oパフォーマンス

アプリケーションのI/Oの問題は「I/O」グループの下の「ソケット読取り」タブをモニターすれば診断できます。

Javaアプリケーションがソケット読取りソケット書込みファイルの読込みまたはファイル書込みに多くの時間を費やしている場合は、I/Oまたはネットワークがボトルネックである可能性があります。アプリケーションのI/Oの問題を診断するには、図4-5に示すように、「I/O」グループの下の「ソケット読取り」タブを見ます。

図4-5 I/Oパフォーマンスの問題 - 「ソケット読取り」タブ

図4-5の説明が続きます
「図4-5 I/Oパフォーマンスの問題 - 「ソケット読取り」タブ」の説明

図4-5では、アプリケーションのリモート・アドレス198.51.100.0からの読取り数は100であると示されています。読み取られたバイト数の合計は356バイトで、待機時間の合計は1分57秒です。左上の「イベント別」タブを選択し、各イベントに費やされた時間と読み取られたデータを分析します。

ファイルまたはネットワークI/Oの問題も同様の方法で診断します。読取り/書込みの最も多いファイルを調べ、各ファイルの読取り/書込みとI/Oにかかった時間を確認します。

デフォルトでは、I/Oのすべてのタブは、期間が20ミリ秒より長いイベントを表示します。フライト記録を開始するとき、より多くのデータを収集するために、ファイルI/Oのしきい値またはソケットI/Oのしきい値を下げることができますが、パフォーマンスへの影響が大きくなる可能性があります。

コード実行パフォーマンス

コード実行パフォーマンスは、Java Mission Control、「呼出しツリー」タブを使用してモニターできます。

Javaアプリケーションのイベントが多くない場合、アプリケーションの主なボトルネックは、実行中のコードである可能性があります。まず、「スレッド」タブを見て、「概要」タブを選択します。CPU使用率の経時的推移を見ます。これは、記録されているJVMのCPU使用率とマシン上の総CPU使用率を示しています。JVMのCPU使用率は低いが、マシンのCPU使用率が高い場合は、他のアプリケーションが多くのCPUを消費していることを意味します。次に、「システム」タブ・グループの「プロセス」タブで、システム上で実行されている他のアプリケーションを見ます。ただし、それらのCPU使用率は表示されない場合があるので、多くのCPUを使用しているプロセスを調べるには、Topまたはタスク・マネージャなどのOSツールを使用する方が簡単です。

アプリケーションが多くのCPU時間を使用している場合は、「コード」タブ・グループを選択し、「ホット・スレッド」タブを見てください。このタブには、最も多くのCPU時間を使用するスレッドが表示されます。ただし、この情報はメソッド・サンプリングに基づいているので、サンプル数が少ない場合には100%正確でないことがあります。JFRが実行されているとき、JVMはスレッドをサンプリングします。デフォルトでは、連続記録ではいくつかのメソッド・サンプリングのみが実行され、プロファイリング記録ではできるかぎり多く実行されます。メソッド・サンプリングでは、コードを実行しているスレッドだけからデータを収集します。I/O待ち、スリープ中、ロック待ちなどのスレッドはサンプリングされません。したがって、メソッド・サンプルが多いスレッドは、CPU時間を最も多く使用しているスレッドですが、各スレッドがどのくらいのCPUを使用しているかはわかりません。

「コード」タブ・グループの「ホット・メソッド」タブは、アプリケーションが実行時間の大半を費やしている場所を見つけるのに役立ちます。このタブには、スタックの上位メソッドによりグループ化されたすべてのサンプルが表示されます。「呼出しツリー」タブを使用して、スタック・トレースの最下位のメソッドから始め、上方に移動します。図4-6では、Thread.runから始めて、最も多くサンプリングされている呼出しを見ています。

図4-6 コード実行パフォーマンス - 「呼出しツリー」タブ

図4-6の説明が続きます
「図4-6 コード実行パフォーマンス - 「呼出しツリー」タブ」の説明