JProfiler ヘルプDownload

ヒープウォーカー


ヒープスナップショット

オブジェクト間の参照を含むヒープ分析にはヒープスナップショットが必要です。なぜなら、JVMにオブジェクトへのインカミング参照を尋ねることはできないからです。その質問に答えるには、ヒープ全体を反復処理する必要があります。そのヒープスナップショットから、JProfilerはヒープウォーカーのビューを提供するために必要なデータを生成するために最適化された内部データベースを作成します。

ヒープスナップショットには2つのソースがあります:JProfilerヒープスナップショットとHPROF/PHDヒープスナップショットです。JProfilerヒープスナップショットはヒープウォーカーで利用可能なすべての機能をサポートしています。プロファイリングエージェントはプロファイリングインターフェースJVMTIを使用してすべての参照を反復処理します。プロファイルされたJVMが異なるマシンで実行されている場合、すべての情報はローカルマシンに転送され、そこでさらに計算が行われます。HPROF/PHDスナップショットはJVMの組み込みメカニズムで作成され、JProfilerが読み取ることができる標準フォーマットでディスクに書き込まれます。HotSpot JVMはHPROFスナップショットを作成でき、Eclipse OpenJ9 JVMはPHDスナップショットを提供します。

ヒープウォーカーの概要ページでは、JProfilerヒープスナップショットまたはHPROF/PHDヒープスナップショットを作成するかを選択できます。デフォルトでは、JProfilerヒープスナップショットが推奨されます。HPROF/PHDヒープスナップショットは、別の章で説明されている特別な状況で役立ちます。

選択ステップ

ヒープウォーカーは、選択されたオブジェクトセットの異なる側面を示すいくつかのビューで構成されています。ヒープスナップショットを取得した直後は、ヒープ上のすべてのオブジェクトを見ています。各ビューには、選択されたオブジェクトを現在のオブジェクトセットに変えるためのナビゲーションアクションがあります。ヒープウォーカーのヘッダーエリアには、現在のオブジェクトセットに含まれるオブジェクトの数に関する情報が表示されます。

最初は、ライブメモリセクションの「すべてのオブジェクト」ビューに似た「クラス」ビューを見ています。クラスを選択して使用→選択されたインスタンスを呼び出すことで、そのクラスのインスタンスのみを含む新しいオブジェクトセットを作成します。ヒープウォーカーでは、「使用する」とは常に新しいオブジェクトセットを作成することを意味します。

新しいオブジェクトセットに対して、ヒープウォーカーのクラスビューを表示することは興味深くありません。なぜなら、それは実質的に以前に選択されたクラスにテーブルをフィルタリングするだけだからです。代わりに、JProfilerは「新しいオブジェクトセット」ダイアログで別のビューを提案します。このダイアログをキャンセルして新しいオブジェクトセットを破棄し、以前のビューに戻ることができます。アウトゴーイング参照ビューが提案されますが、別のビューを選択することもできます。これは最初に表示されるビューに過ぎません。その後、ヒープウォーカーのビューセレクターでビューを切り替えることができます。

ヘッダーエリアには、現在2つの選択ステップがあることが示され、保持サイズとディープサイズを計算するためのリンクや、現在のオブジェクトセットによって保持されているすべてのオブジェクトを使用するためのリンクが含まれています。後者は別の選択ステップを追加し、オブジェクトセットに複数のクラスが含まれる可能性があるため、クラスビューを提案します。

ヒープウォーカーの下部には、これまでの選択ステップが一覧表示されています。ハイパーリンクをクリックすると、任意の選択ステップに戻ることができます。最初のデータセットは、ツールバーのスタートに移動ボタンでもアクセスできます。ツールバーの戻るボタンと進むボタンは、分析でバックトラックする必要がある場合に便利です。

クラスビュー

ヒープウォーカーの上部にあるビューセレクターには、現在のオブジェクトセットに対する異なる情報を示す5つのビューが含まれています。その最初のものが「クラス」ビューです。

クラスビューは、ライブメモリセクションの「すべてのオブジェクト」ビューに似ており、クラスをパッケージにグループ化できる集約レベルの選択肢があります。さらに、クラスの推定保持サイズを表示することができます。これは、クラスのすべてのインスタンスがヒープから削除された場合に解放されるメモリの量です。推定保持サイズを計算ハイパーリンクをクリックすると、新しい保持サイズ列が追加されます。表示される保持サイズは推定された下限であり、正確な数値を計算するには時間がかかりすぎます。本当に正確な数値が必要な場合は、興味のあるクラスまたはパッケージを選択し、新しいオブジェクトセットのヘッダーにある保持サイズとディープサイズを計算ハイパーリンクを使用してください。

1つ以上のクラスまたはパッケージを選択すると、インスタンス自体、関連するjava.lang.Classオブジェクト、またはすべての保持オブジェクトを選択できます。ダブルクリックは最も迅速な選択モードであり、選択されたインスタンスを使用します。複数の選択モードが利用可能な場合、このケースのように、ビューの上に使用ドロップダウンメニューが表示されます。

クラスローダー関連の問題を解決する際には、インスタンスをクラスローダーでグループ化する必要があることがよくあります。インスペクションタブには、クラスビューで利用可能な「クラスローダーでグループ化」インスペクションがあり、そのコンテキストで特に重要です。その分析を実行すると、上部にあるグループ化テーブルにすべてのクラスローダーが表示されます。クラスローダーを選択すると、以下のビューでデータがそれに応じてフィルタリングされます。別の選択ステップを実行するまで、グループ化テーブルはヒープウォーカーの他のビューに切り替えてもそのまま残ります。その後、クラスローダーの選択がその選択ステップの一部になります。

割り当て記録ビュー

オブジェクトがどこで割り当てられたかの情報は、メモリリークの疑いを絞り込む際やメモリ消費を削減しようとする際に重要です。JProfilerヒープスナップショットの場合、「割り当て」ビューは、割り当てコールツリーと割り当てホットスポットを示します。割り当てが記録されたオブジェクトに対して、割り当てコールツリーに「未記録オブジェクト」ノードにグループ化されます。HPROF/PHDスナップショットの場合、このビューは利用できません。

クラスビューと同様に、複数のノードを選択し、上部の選択されたものを使用ボタンを使用して新しい選択ステップを作成できます。「割り当てホットスポット」ビューのモードでは、バックトレース内のノードも選択できます。これにより、選択されたバックトレースで終了するコールスタックで割り当てられた、関連するトップレベルホットスポットのオブジェクトのみが選択されます。

JProfilerが割り当てを記録する際に保存できるもう1つの情報は、オブジェクトが割り当てられた時間です。ヒープウォーカーの「時間」ビューは、現在のオブジェクトセット内のすべての記録されたインスタンスの割り当て時間のヒストグラムを示します。クリックしてドラッグすることで、1つまたは複数の間隔を選択し、選択されたものを使用ボタンで新しいオブジェクトセットを作成できます。

時間間隔をより正確に選択するために、ブックマークの範囲を指定できます。最初と最後に選択されたブックマークの間のすべてのオブジェクトがマークされます。

時間ビューに加えて、割り当て時間は参照ビューの別の列として表示されます。ただし、割り当て時間の記録はデフォルトでは有効になっていません。時間ビューで直接オンにするか、セッション設定ダイアログの詳細設定 -> メモリプロファイリングで設定を編集できます。

最大オブジェクトビュー

最大オブジェクトビューは、現在のオブジェクトセット内の最も重要なオブジェクトのリストを表示します。このコンテキストでの「最大」とは、ヒープから削除された場合に最も多くのメモリを解放するオブジェクトを意味します。そのサイズは保持サイズと呼ばれます。対照的に、ディープサイズは、強い参照を通じて到達可能なすべてのオブジェクトの合計サイズです。

各オブジェクトは、他のオブジェクトへのアウトゴーイング参照を表示するために展開できます。この方法で、祖先の1つが削除された場合にガベージコレクトされる保持オブジェクトのツリーを再帰的に展開できます。この種のツリーは「ドミネーターツリー」と呼ばれます。このツリー内の各オブジェクトに表示される情報は、アウトゴーイング参照ビューと似ていますが、支配的な参照のみが表示されます。

すべての支配されたオブジェクトがその支配者によって直接参照されるわけではありません。たとえば、次の図の参照を考えてみましょう:

GCルート直接支配します直接支配します間接的に支配しますObject AObject B2Object B1Object C

オブジェクトAはオブジェクトB1とB2を支配し、オブジェクトCへの直接参照を持っていません。B1とB2の両方がCを参照しています。B1もB2もCを支配していませんが、Aは支配しています。この場合、B1、B2、およびCはドミネーターツリーのAの直接の子としてリストされ、CはB1とB2の子としてリストされません。B1とB2の場合、Aで保持されているフィールド名が表示されます。Cの場合、参照ノードに「[推移的参照]」が表示されます。

ドミネーターツリーの各参照ノードの左側には、トップレベルオブジェクトの保持サイズの何パーセントがターゲットオブジェクトによってまだ保持されているかを示すサイズバーがあります。ツリーをさらに掘り下げると、数値は減少します。ビュー設定では、パーセンテージの基準をヒープ全体のサイズに変更できます。

ドミネーターツリーには、親オブジェクトの保持サイズの0.5%未満の保持サイズを持つすべてのオブジェクトを排除する組み込みのカットオフがあります。これは、重要なオブジェクトから気をそらす小さな支配されたオブジェクトの非常に長いリストを避けるためです。このようなカットオフが発生すると、このレベルで表示されていないオブジェクトの数、その合計保持サイズ、および単一オブジェクトの最大保持サイズを通知する特別な「カットオフ」子ノードが表示されます。

単一のオブジェクトを表示する代わりに、ドミネーターツリーは最大オブジェクトをクラスにグループ化することもできます。ビューの上部にあるグループ化ドロップダウンには、この表示モードをアクティブにするチェックボックスが含まれています。さらに、トップレベルでクラスローダーのグループ化を追加できます。クラスローダーのグループ化は、最大オブジェクトが計算された後に適用され、最大オブジェクトのクラスを誰がロードしたかを示します。特定のクラスローダーの最大オブジェクトを分析したい場合は、最初に「クラスローダーでグループ化」インスペクションを使用できます。

最大オブジェクトビューの上にある表示モードセレクターを使用すると、サンバーストダイアグラムに切り替えることができます。このダイアグラムは、一連の同心円状のセグメントリングで構成されており、最大深度までのドミネーターツリーの全体の内容を1つの画像で示します。参照は最も内側のリングから始まり、円の外縁に向かって伝播します。この視覚化は、高情報密度の平坦な視点を提供し、参照パターンを発見し、特別な色分けを通じて大きなプリミティブおよびオブジェクト配列を一目で確認できるようにします。

現在のオブジェクトセットがヒープ全体である場合、円の全周は使用されたヒープサイズに対応します。最大オブジェクトビューは、ヒープ全体の0.1%以上を保持するオブジェクトのみを表示するため、最大オブジェクトによって保持されていないすべてのオブジェクトに対応する実質的なセクターが空になります。

任意のリングセグメントをクリックすると、円の新しいルートが設定され、ダイアグラムで確認できる最大深度が拡張されます。ダイアグラムの中空の中心をクリックすると、以前のルートが復元されます。新しいルートが設定されている場合、円の全周はルートオブジェクトの保持サイズに対応します。空のセクターは、ルートオブジェクトの自己サイズと、最大保持オブジェクトのリストに存在しない追加のオブジェクトを表します。現在のオブジェクトセットがヒープ全体でない場合、円の全周は表示されている最大オブジェクトの合計に対応し、空のセクターは表示されません。

インスタンスとその直ちに保持されたオブジェクトに関する詳細情報は、マウスを上に移動するとダイアグラムの右側に表示されます。マウスがリングセグメントの外にある場合、右側のリストには最も内側のリングの最大オブジェクトが表示されます。そのリストにマウスを移動すると、対応するリングセグメントがハイライトされ、リスト項目をクリックするとダイアグラムの新しいルートが設定されます。新しいオブジェクトセットを作成するには、リングセグメントやリスト項目のコンテキストメニューのアクションから選択できます。

参照ビュー

前のビューとは異なり、参照ビューは少なくとも1つの選択ステップを実行した場合にのみ利用可能です。初期オブジェクトセットに対しては、これらのビューは役に立ちません。なぜなら、インカミングおよびアウトゴーイング参照ビューはすべての個々のオブジェクトを表示し、マージされた参照ビューは特定のオブジェクトセットに対してのみ解釈できるからです。

アウトゴーイング参照ビューは、IDEのデバッガーが表示するビューに似ています。オブジェクトを開くと、プリミティブデータと他のオブジェクトへの参照が表示されます。任意の参照タイプを新しいオブジェクトセットとして選択でき、複数のオブジェクトを一度に選択できます。クラスビューと同様に、保持オブジェクトや関連するjava.lang.Classオブジェクトを選択できます。選択されたオブジェクトが標準コレクションの場合、単一のアクションで含まれるすべての要素を選択することもできます。クラスローダーオブジェクトの場合、ロードされたすべてのインスタンスを選択するオプションがあります。

null参照を持つフィールドは、メモリ分析の際に気をそらす可能性があるため、デフォルトでは表示されません。デバッグ目的でフィールドをすべて表示したい場合は、ビュー設定でこの動作を変更できます。

表示されたインスタンスの単純な選択に加えて、アウトゴーイング参照ビューには、強力なフィルタリング機能があります。ライブセッションでは、アウトゴーイングおよびインカミング参照ビューの両方に、同じ章で説明されている高度な操作および表示機能があります。

インカミング参照ビューは、メモリリークを解決するための主要なツールです。オブジェクトがなぜガベージコレクトされないのかを調べるために、GCルートへのパスを表示ボタンは、ガベージコレクタールートへの参照チェーンを見つけます。メモリリークに関する章には、この重要なトピックに関する詳細情報があります。

マージされた参照

多くの異なるオブジェクトの参照を確認するのは面倒な場合があるため、JProfilerは現在のオブジェクトセット内のすべてのオブジェクトのマージされたアウトゴーイングおよびインカミング参照を表示できます。デフォルトでは、参照はクラスごとに集約されます。クラスのインスタンスが同じクラスの他のインスタンスによって参照されている場合、 特別なノードが挿入され、これらのクラス再帰参照からの元のインスタンスとインスタンスを示します。このメカニズムは、リンクリストのような一般的なデータ構造内の内部参照チェーンを自動的に折りたたみます。

フィールドごとにグループ化されたマージされた参照を表示することもできます。その場合、各ノードはクラスの特定のフィールドや配列の内容などの参照タイプです。標準コレクションの場合、累積を妨げる内部参照チェーンが圧縮されるため、「java.lang.HashMapのマップ値」のような参照タイプが表示されます。クラス集約の場合とは異なり、このメカニズムはJREの標準ライブラリから明示的にサポートされているコレクションに対してのみ機能します。

「マージされたアウトゴーイング参照」ビューでは、インスタンスカウントは参照されたオブジェクトを指します。「マージされたインカミング参照」ビューでは、各行に2つのインスタンスカウントが表示されます。最初のインスタンスカウントは、現在のオブジェクトセット内のインスタンスがこのパスに沿って参照されている数を示します。ノードの左側にあるバーアイコンは、この割合を視覚化します。矢印アイコンの後の2番目のインスタンスカウントは、親ノードへの参照を保持しているオブジェクトを指します。選択ステップを実行する際に、選択された方法で参照されている現在のオブジェクトセットからオブジェクトを選択するか、選択された参照を持つオブジェクト(参照ホルダー)に興味があるかを選択できます。

「マージされた支配参照」ビューを使用すると、現在のオブジェクトセット内の一部またはすべてのオブジェクトがガベージコレクトされるために削除する必要がある参照を見つけることができます。支配参照ツリーは、最大オブジェクトビューのドミネーターツリーのマージされた逆として解釈でき、クラスごとに集約されます。参照矢印は、2つのクラス間の直接参照を表していない場合がありますが、支配的でない参照を保持している他のクラスが間にある場合があります。複数のガベージコレクタールートがある場合、現在のオブジェクトセット内の一部またはすべてのオブジェクトに対して支配参照が存在しない場合があります。

デフォルトでは、「マージされた支配参照」ビューはインカミング支配参照を表示し、ツリーを開くことで、GCルートによって保持されているオブジェクトに到達できます。時には、参照ツリーが多くの異なるパスに沿って同じルートオブジェクトに導くことがあります。ビューの上部にあるドロップダウンで「GCルートからオブジェクトへのビュー」モードを選択することで、ルートがトップレベルにあり、現在のオブジェクトセットがリーフノードにある逆の視点を見ることができます。その場合、参照はトップレベルからリーフノードに向かって進みます。どの視点がより良いかは、削除したい参照が現在のオブジェクトセットに近いか、GCルートに近いかによります。

インスペクション

「インスペクション」ビューはデータ自体を表示しません。他のビューでは利用できないルールに従って新しいオブジェクトセットを作成するいくつかのヒープ分析を提示します。たとえば、スレッドローカルによって保持されているすべてのオブジェクトを表示したい場合があります。これは参照ビューでは不可能です。インスペクションは、いくつかのカテゴリにグループ化され、その説明で説明されています。

インスペクションは、計算されたオブジェクトセットをグループに分割することができます。グループは、ヒープウォーカーの上部にあるテーブルに表示されます。たとえば、「重複する文字列」インスペクションは、重複する文字列値をグループとして表示します。参照ビューにいる場合、選択された文字列値を持つjava.lang.Stringインスタンスを以下に表示できます。最初は、グループテーブルの最初の行が選択されています。選択を変更することで、現在のオブジェクトセットが変更されます。グループテーブルのインスタンスカウントおよびサイズ列は、行を選択したときに現在のオブジェクトセットがどれだけ大きくなるかを示します。

グループ選択は、ヒープウォーカーの別の選択ステップではありませんが、インスペクションによって行われた選択ステップの一部になります。グループ選択は、下部の選択ステップペインに表示されます。グループ選択を変更すると、選択ステップペインが即座に更新されます。

グループを作成する各インスペクションは、インスペクションのコンテキストで最も重要なグループを決定します。これは、他の列の自然なソート順と常に一致するわけではないため、グループテーブルの優先度列には、インスペクションのソート順を強制する数値が含まれています。

インスペクションは、大きなヒープに対して計算するのに高価な場合があるため、結果はキャッシュされます。このようにして、履歴に戻って、以前に計算されたインスペクションの結果を待たずに確認できます。

ヒープウォーカーグラフ

インスタンスとその参照を一緒に最も現実的に表現するのはグラフです。グラフは視覚的な密度が低く、一部のタイプの分析には不向きですが、それでもオブジェクト間の関係を視覚化する最良の方法です。たとえば、循環参照はツリーでは解釈が難しいですが、グラフではすぐに明らかです。また、ツリーストラクチャではどちらか一方しか表示できないため、インカミングおよびアウトゴーイング参照を一緒に表示することが有益な場合があります。

ヒープウォーカーグラフは、現在のオブジェクトセットから自動的にオブジェクトを表示することはなく、現在のオブジェクトセットを変更してもクリアされません。アウトゴーイング参照ビュー、インカミング参照ビュー、または最大オブジェクトビューから選択したオブジェクトを手動でグラフに追加し、1つ以上のインスタンスを選択してグラフに表示アクションを使用します。

グラフ内のパッケージ名はデフォルトで短縮されています。CPUコールグラフと同様に、ビュー設定で完全な表示を有効にできます。参照は矢印として描かれます。参照上にマウスを移動すると、特定の参照の詳細を示すツールチップウィンドウが表示されます。参照ビューから手動で追加されたインスタンスは青い背景を持っています。インスタンスが追加された時期が新しいほど、背景色は暗くなります。ガベージコレクタールートは赤い背景を持ち、クラスは黄色い背景を持ちます。

デフォルトでは、参照グラフは現在のインスタンスの直接のインカミングおよびアウトゴーイング参照のみを表示します。任意のオブジェクトをダブルクリックすることでグラフを展開できます。これにより、そのオブジェクトの直接のインカミングまたは直接のアウトゴーイング参照が展開されます。インスタンスの左側と右側にある展開コントロールを使用して、インカミングおよびアウトゴーイング参照を選択的に開くことができます。バックトラックする必要がある場合は、グラフの以前の状態を復元するために元に戻す機能を使用して、ノードが多すぎて気が散らないようにします。グラフをトリミングするには、すべての接続されていないノードを削除するアクションや、すべてのオブジェクトを削除するアクションがあります。

インカミング参照ビューと同様に、グラフにはGCルートへのパスを表示ボタンがあり、利用可能な場合は1つ以上の参照チェーンをガベージコレクタールートに展開します。さらに、2つのインスタンスが選択されている場合にアクティブになる2つの選択されたノード間のパスを見つけるアクションがあります。これは、弱い参照に沿っても、指向性および非指向性のパスを検索できます。適切なパスが見つかると、それは赤で表示されます。

初期オブジェクトセット

ヒープスナップショットを取得する際に、初期オブジェクトセットを制御するオプションを指定できます。割り当てを記録している場合、記録されたオブジェクトを選択チェックボックスは、最初に表示されるオブジェクトを記録されたものに制限します。通常、これらの数値はライブメモリビューのものとは異なります。なぜなら、ヒープウォーカーによって参照されていないオブジェクトが削除されるからです。未記録のオブジェクトはヒープスナップショットにまだ存在していますが、初期オブジェクトセットには表示されません。さらに選択ステップを進めることで、未記録のオブジェクトに到達できます。

さらに、ヒープウォーカーはガベージコレクションを実行し、ソフト参照を除いて弱参照オブジェクトを削除します。これは通常、メモリリークを探している場合に望ましいです。なぜなら、弱参照オブジェクトは気をそらす可能性があり、強参照オブジェクトのみが関連しているからです。ただし、弱参照オブジェクトに興味がある場合は、ヒープウォーカーにそれらを保持させることができます。JVMの4つの弱参照タイプは「ソフト」、「弱」、「ファントム」、「ファイナライザ」であり、ヒープスナップショットでオブジェクトを保持するのに十分なものを選択できます。

存在する場合、弱参照オブジェクトはヒープウォーカーの「弱参照」インスペクションを使用して現在のオブジェクトセットから選択または削除できます。

ヒープのマーク

特定のユースケースのために割り当てられたオブジェクトを確認したい場合があります。割り当て記録をそのユースケースの周りで開始および停止することでこれを行うこともできますが、オーバーヘッドが少なく、他の目的のために割り当て記録機能を保持するはるかに優れた方法があります:ヒープウォーカーの概要で宣伝されているヒープをマークアクションであり、プロファイリングメニューやトリガーアクションとしても利用可能です。これにより、ヒープ上のすべてのオブジェクトが「古い」としてマークされます。次のヒープスナップショットを取得すると、「新しい」オブジェクトが何であるべきかが明確になります。

以前のヒープスナップショットまたはヒープマークの呼び出しがあった場合、ヒープウォーカーのタイトルエリアには新しいインスタンスカウントと、新しいものを使用および古いものを使用というタイトルの2つのリンクが表示されます。これにより、その時点から割り当てられたインスタンス、またはそれ以前に割り当てられた生存インスタンスのいずれかを選択できます。この情報は各オブジェクトセットに対して利用可能であり、最初に掘り下げてから後で新しいまたは古いインスタンスを選択できます。