JProfiler ヘルプ

ガーベジコレクター解析

ガーベジコレクター(GC)のランタイム特性を理解し、解析することは、いくつかの理由で重要です。まず、GCによる停止(GCポーズ)はアプリケーションの応答性に直接影響します。 ガーベジコレクターの動作を把握することで、設定を最適化し、これらのポーズを短縮することができます。 一般的に、頻繁かつ長時間のGCサイクルが発生している場合、ヒープが小さすぎるか、一時オブジェクトが多く生成されている可能性があります。

ガーベジコレクタープローブを活用することで、これらの問題を解決し、JVM設定のチューニング時に、適切なガーベジコレクターやヒープサイズ、その他のJVMパラメータの選択など、より的確な判断ができるようになります。

ガーベジコレクタープローブは、他のプローブとは異なるビューとデータソースを持っています。 このプローブはJVMのプロファイリングインターフェースからデータを取得するのではなく、JFRストリーミングを利用してGC関連イベントを JDK Flight Recorderから解析します。そのため、JFRイベントストリーミングに依存しており、GCプローブはJava 17以降のHotSpot JVMでプロファイルする場合のみ利用可能です。 JFRスナップショットを開くと、使用しているJavaバージョンに関係なく、同じプローブが利用できます。

ガーベジコレクションビュー

ガーベジコレクタープローブのメインビューは「Garbage collections」テーブルです。このテーブルには、記録されたすべてのガーベジコレクションが行として表示され、主要なメトリクスが列として示されます。

「Cause」列には、ガーベジコレクションがトリガーされた理由が表示されます。例えば、 System.gc()の呼び出しによってフルガーベジコレクションがトリガーされた場合、その「Collector」列には「G1Full」と表示されます。 また、20msという大きなポーズが発生していることから、一般的にSystem.gc()の呼び出しは推奨されません。 その他の原因としては、ヤング世代領域のコレクション(「G1New」)や、G1コレクターのオールドGCコレクション(「G1Old」)による、オールド世代の未参照オブジェクトのクリーンアップなどがあります。 オールドGCコレクションは、ヤング世代コレクションよりも一貫して長い時間がかかる一方で、ヤング世代コレクションの方が多くのオブジェクトを回収していることが分かります。

特別なGC処理が行われる参照は、「final」「weak」「soft」「phantom」参照として、それぞれ別の列に表示されます。

最長ポーズとポーズ合計の列が分かれている理由は、各ガーベジコレクションが複数のフェーズで構成され、それぞれが個別のポーズを発生させるためです。 また、ガーベジコレクションの「Duration」はポーズ合計と等しくありません。なぜなら、ガーベジコレクションの実行中、JVMが部分的にしか停止しないためです。 スクリーンショットの「G1Old」コレクションでは、全体の約5分の1の時間しかJVMが停止していないことが分かります。

ガーベジコレクションの各フェーズを確認するには、「GC ID」列のツリーアイコンを切り替えてください。

上記のスクリーンショットでは、G1コレクターのミックスGCコレクション(「G1Old」)が展開されています。 ほとんどの時間が「Class Unloading」に費やされていますが、これはJVMを停止させません。 右側にはガーベジコレクションのさらなる統計情報が表示されています。ここでは、使用中のヒープは変化せず、使用中のメタスペースが0.1%増加しています。

各コレクターのフェーズは異なります。上記のスクリーンショットでは、フルコレクションが表示されています。 この場合、ヒープ全体のライブオブジェクトのマーキングに多くの時間が費やされています。 コレクション終了時には、使用ヒープが15.7%減少し、メタスペースは変化していません。

ガーベジコレクションを解析する際、フィルタリングは異なるサブセットを比較するための重要なツールです。 テーブル上部にはフィルタセレクターがあり、任意の列を選択して対応するフィルタを設定できます。 より簡単に類似のガーベジコレクションを確認したい場合は、テーブルのコンテキストメニューから、選択した行の列値に基づくフィルタ条件を選択できます。

複数のフィルタを追加して、関心のあるガーベジコレクションを絞り込むことができます。 有効なフィルタはテーブル上部にラベルとして表示されます。また、ネストされたGCフェーズテーブルからもフィルタを追加できます。

テレメトリー

GCプローブは複数のテレメトリーを生成し、「Telemetries」プローブビューで利用できます。

GCポーズの最小化に関心がある場合は、最上部の「Longest pause」テレメトリーが最も重要です。 テレメトリーの時間軸をドラッグして、「Garbage Collections」ビューで対応するガーベジコレクションを選択できます。 垂直方向の解像度を高めたい場合は、上部のドロップダウンやテレメトリー名のクリックで、単一のテレメトリーを選択できます。

上記のスクリーンショットでは、時間ごとのポーズ合計が表示されています。 JProfilerは、合計可能な測定値を記録データのヒストグラムとして表示します。 ビン幅は利用可能な水平スペースに依存するため、ヒストグラムのビンはズームレベルや「scale to fit」が有効な場合、ウィンドウ幅によって変化します。 ただし、すべてのヒストグラムビンの下の面積合計は変わりません。

ヒープおよびメタスペースのテレメトリーは、ガーベジコレクションを展開した際に表示される統計情報に基づいています。 これは、フルプロファイリングセッションのメモリテレメトリーのように定期的にサンプリングされているわけではありません。 一定期間内にガーベジコレクションが発生しなければ、データはありません。 割り当てアクティビティが少ないJVMでは、時間軸上で2つのガーベジコレクション間が長く補間される場合があります。

これらの各テレメトリーには「Before GC」と「After GC」の2本のデータラインがあります。 特に「Used Heap」テレメトリーでは、両者の差が大きくなる傾向があります。 各時点で、2本のデータラインの値を比較することで、ガーベジコレクションがどれだけ作業を行ったかを確認できます。 ツールチップで正確な値を確認することも可能です。 「Committed heap」テレメトリーやメタスペースのテレメトリーでは、両ラインの差は小さい場合が多いです。

JFRスナップショットを解析している場合、 jdk.GCHeapSummary JFRイベントタイプの同じデータが、テレメトリーセクションの「Memory」テレメトリーにも使用されます。 ただし、この場合は「Before GC」と「After GC」の値が同じデータラインで表示され、GCプローブのテレメトリーのように1秒ごとに集約されないため、グラフの見た目が異なります。

GCサマリー

GCサマリーでは、記録期間全体にわたって集約された測定値が表示されます。 各測定値には、ガーベジコレクションの回数、平均値、最大値、合計値が示されます。 最も重要なデータは上部の「Pause times」で、これはアプリケーションの生存性に直接影響します。

他のトップレベルカテゴリでは、すべてのコレクションの合計時間が表示され、それがヤングコレクションとオールドコレクションの2つのサブカテゴリに分割されます。

GC設定

ガーベジコレクターのチューニング時には、明示的に設定できる、またはガーベジコレクター自身によって暗黙的に設定される共通プロパティを確認したい場合があります。

これらのプロパティはすべてのガーベジコレクターに共通しており、ガーベジコレクター間の違いを理解するのに役立ちます。

GCフラグ

最後に、GC固有のフラグによって、ガーベジコレクターでチューニング可能なプロパティを把握し、実際の値を確認できます。

「Origin」列には、フラグがどのように設定されたかが表示されます。 「Default」は標準設定から変更されていない値、「Ergonomic」はガーベジコレクターによって自動調整されたフラグです。 コマンドラインで特定のGCフラグを設定した場合は、「Command line」として表示されます。