JProfiler ヘルプDownload

メモリプロファイリング


ヒープ上のオブジェクトに関する情報を取得する方法は2つあります。1つは、プロファイリングエージェントが各オブジェクトの割り当てとガベージコレクションを追跡する方法です。JProfilerでは、これを「割り当て記録」と呼びます。これにより、オブジェクトがどこで割り当てられたかを知ることができ、一時オブジェクトに関する統計を作成することもできます。もう1つは、JVMのプロファイリングインターフェースが「ヒープスナップショット」を取得し、すべてのライブオブジェクトとその参照を調査する方法です。この情報は、オブジェクトがなぜガベージコレクションされないのかを理解するために必要です。

割り当て記録とヒープスナップショットの両方は高価な操作です。割り当て記録は、java.lang.Object コンストラクタを計測し、ガベージコレクタがプロファイリングインターフェースに継続的に報告しなければならないため、ランタイム特性に大きな影響を与えます。これが、デフォルトで割り当てが記録されない理由であり、記録を開始および停止する必要があります。ヒープスナップショットを取得するのは一度限りの操作です。しかし、JVMを数秒間停止させる可能性があり、取得したデータの分析には、ヒープのサイズに応じて比較的長い時間がかかることがあります。

JProfilerはメモリ分析を2つのビューセクションに分割します。「ライブメモリ」セクションは定期的に更新できるデータを表示し、「ヒープウォーカー」セクションは静的なヒープスナップショットを表示します。割り当て記録は「ライブメモリ」セクションで制御されますが、記録されたデータはヒープウォーカーによっても表示されます。

メモリプロファイリングで解決できる最も一般的な3つの問題は、メモリリークの発見、メモリ消費の削減、一時オブジェクトの作成の削減です。最初の2つの問題については、主にヒープウォーカーを使用し、主にJVM内の最大のオブジェクトを保持しているのが誰であるか、そしてそれらがどこで作成されたかを調べます。最後の問題については、ガベージコレクションされたオブジェクトを含むライブビューにのみ依存することができます。

インスタンス数の追跡

ヒープ上にどのようなオブジェクトがあるかを把握するために、「すべてのオブジェクト」ビューはすべてのクラスとそのインスタンス数のヒストグラムを表示します。このビューに表示されるデータは、割り当て記録ではなく、インスタンス数のみを計算するミニヒープスナップショットを実行することで収集されます。ヒープが大きいほど、この操作を実行するのに時間がかかるため、このビューは現在の値で自動的に更新されません。

メモリリークを探す際には、インスタンス数を時間とともに比較したいことがよくあります。すべてのクラスについてそれを行うには、ビューの差分機能を使用できます。すべてのオブジェクトの2つのダンプが同時に選択されると、差分列が挿入され、インスタンス数のヒストグラムは緑色でマーク時の基準値を示します。すべてのオブジェクトの新しいダンプを取得すると、最も古い選択されたダンプが選択されたままになり、すべてのオブジェクトの新しいダンプとの違いが表示されます。

ダンプセレクタは、ダンプが取得された時刻を示します。ダブルクリックでラベルを追加して、識別を容易にすることができます。すべてのオブジェクトのダンプは、トリガーアクションまたはController APIでもトリガーでき、ラベルを指定することもできます。

一方、「記録されたオブジェクト」ビューは、割り当て記録を開始した後に割り当てられたオブジェクトのインスタンス数のみを表示します。割り当て記録を停止すると、新しい割り当ては追加されませんが、ガベージコレクションは追跡され続けます。このようにして、特定のユースケースでヒープに残るオブジェクトを確認できます。オブジェクトが長時間ガベージコレクションされないことに注意してください。GC実行ツールバーボタンを使用して、このプロセスを加速できます。動的に更新されるほとんどのビューと同様に、フリーズツールバーボタンを使用して表示されるデータの更新を停止できます。

現在をマークツールバーボタンを使用すると、「記録されたオブジェクト」ビューでも選択された基準に対する差分列を表示できます。選択されたクラスについては、コンテキストメニューの選択をクラス・トラッカーに追加アクションを使用して、時間解決されたグラフを表示することもできます。

割り当てスポット

割り当て記録がアクティブな場合、JProfilerはオブジェクトが割り当てられるたびに呼び出しスタックを記録します。スタックウォーキングAPIからの正確な呼び出しスタックは使用しません。なぜなら、それは非常に高価だからです。代わりに、CPUプロファイリングに設定されたのと同じメカニズムが使用されます。つまり、呼び出しスタックは呼び出しツリーフィルタに従ってフィルタリングされ、実際の割り当てスポットは、無視されたクラスやコンパクトフィルタされたクラスからのメソッドであるため、呼び出しスタックに存在しない場合があります。しかし、これらの変更は直感的に理解しやすいです。コンパクトフィルタされたメソッドは、コンパクトフィルタされたクラスへのさらなる呼び出しで行われるすべての割り当てに対して責任を負います。

サンプリングを使用すると、割り当てスポットが近似的になり、混乱を招くことがあります。時間測定とは異なり、特定のクラスがどこで割り当てられるか、どこで割り当てられないかについて明確なアイデアを持っていることがよくあります。サンプリングは統計的な絵を描くため、java.util.HashMap.getが自分のクラスを割り当てるような、明らかに不可能な割り当てスポットが表示されることがあります。正確な数値や呼び出しスタックが重要な分析には、計測とともに割り当て記録を使用することをお勧めします。

CPUプロファイリングと同様に、割り当て呼び出しスタックは呼び出しツリーとして表示され、呼び出し回数や時間ではなく、割り当て数と割り当てられたメモリが表示されます。CPU呼び出しツリーとは異なり、割り当て呼び出しツリーは自動的に表示および更新されません。なぜなら、ツリーの計算がより高価だからです。JProfilerは、すべてのオブジェクトだけでなく、選択されたクラスやパッケージの割り当てツリーも表示できます。他のオプションとともに、現在のデータから割り当てツリーを計算するようにJProfilerに依頼した後に表示されるオプションダイアログで設定されます。

CPU呼び出しツリーの便利な特性は、各ノードが子ノードで費やされた時間を含むため、上から下に累積時間を追跡できることです。デフォルトでは、割り当てツリーも同じように動作し、各ノードが子ノードによって行われた割り当てを含みます。たとえ割り当てが呼び出しツリーの深い葉ノードでのみ行われたとしても、数値は上に伝播します。このようにして、割り当て呼び出しツリーのブランチを開く際にどのパスを調査する価値があるかを常に確認できます。「自己割り当て」は、実際にノードによって行われたものであり、その子孫によって行われたものではありません。CPU呼び出しツリーと同様に、パーセンテージバーは異なる色で表示されます。

割り当て呼び出しツリーでは、特に選択されたクラスの割り当てを表示する場合、割り当てがまったく行われないノードが多く存在します。これらのノードは、実際の割り当てが行われたノードに至る呼び出しスタックを示すためにのみ存在します。これらのノードはJProfilerでは「ブリッジ」ノードと呼ばれ、上のスクリーンショットのように灰色のアイコンで表示されます。場合によっては、割り当ての累積が邪魔になり、実際の割り当てスポットのみを表示したいことがあります。割り当てツリーのビュー設定ダイアログには、その目的のために非累積数値を表示するオプションがあります。有効にすると、ブリッジノードは常にゼロの割り当てを表示し、パーセンテージバーを持ちません。

割り当てホットスポットビューは、割り当て呼び出しツリーとともにポピュレートされ、選択されたクラスを作成する責任があるメソッドに直接焦点を当てることができます。記録されたオブジェクトビューと同様に、割り当てホットスポットビューは現在の状態をマークし、時間とともに変化を観察することをサポートします。差分列がビューに追加され、現在の値をマークアクションが呼び出された時点からホットスポットがどの程度変化したかを示します。デフォルトでは、割り当てビューは定期的に更新されないため、計算ツールバーボタンをクリックして新しいデータセットを取得し、基準値と比較する必要があります。オプションダイアログで自動更新が利用可能ですが、大きなヒープサイズには推奨されません。

割り当て記録率

すべての割り当てを記録することは、かなりのオーバーヘッドを追加します。多くの場合、割り当ての総数は重要ではなく、相対的な数値が問題を解決するのに十分です。これが、JProfilerがデフォルトで10回に1回の割り当てのみを記録する理由です。これにより、すべての割り当てを記録するのと比較して、オーバーヘッドが約1/10に減少します。すべての割り当てを記録したい場合や、目的に対してさらに少ない割り当てが十分である場合は、記録されたオブジェクトビューや割り当て呼び出しツリーおよびホットスポットビューのパラメータダイアログで記録率を変更できます。

この設定は、「詳細設定->メモリプロファイリング」ステップのセッション設定ダイアログでも見つけることができ、オフラインプロファイリングセッション用に調整できます。

割り当て記録率は、「記録されたオブジェクト」と「記録されたスループット」のVMテレメトリーに影響を与え、その値は設定された分数で測定されます。スナップショットを比較する際には、最初のスナップショットの割り当て率が報告され、必要に応じて他のスナップショットがそれに応じてスケーリングされます。

割り当てられたクラスの分析

割り当てツリーと割り当てホットスポットビューを計算する際には、事前に見たいクラスやパッケージを指定する必要があります。特定のクラスにすでに焦点を当てている場合にはうまく機能しますが、事前の予想なしに割り当てホットスポットを見つけようとする場合には不便です。1つの方法は、「記録されたオブジェクト」ビューを見て、選択したクラスやパッケージの割り当てツリーまたは割り当てホットスポットビューに切り替えるためのコンテキストメニューのアクションを使用することです。

もう1つの方法は、すべてのクラスの割り当てツリーまたは割り当てホットスポットから始めて、クラスを表示アクションを使用して、選択された割り当てスポットまたは割り当てホットスポットのクラスを表示することです。

割り当てられたクラスのヒストグラムは、呼び出しツリー分析として表示されます。このアクションは他の呼び出しツリー分析からも機能します。

クラス分析ビューは静的であり、割り当てツリーとホットスポットビューが再計算されても更新されません。分析を再読み込みアクションは、最初に割り当てツリーを更新し、新しいデータから現在の分析ビューを再計算します。

ガベージコレクションされたオブジェクトの分析

割り当て記録は、ライブオブジェクトを表示するだけでなく、ガベージコレクションされたオブジェクトに関する情報も保持します。これは、一時的な割り当てを調査する際に役立ちます。多くの一時オブジェクトを割り当てることは、かなりのオーバーヘッドを生む可能性があるため、割り当て率を下げることでパフォーマンスが大幅に向上することがあります。

記録されたオブジェクトビューでガベージコレクションされたオブジェクトを表示するには、生存性セレクタをガベージコレクションされたオブジェクトまたはライブおよびガベージコレクションされたオブジェクトに変更します。割り当て呼び出しツリーおよび割り当てホットスポットビューのオプションダイアログには同等のドロップダウンがあります。

しかし、JProfilerはデフォルトでガベージコレクションされたオブジェクトの割り当てツリー情報を収集しません。なぜなら、ライブオブジェクトのみのデータは、はるかに少ないオーバーヘッドで維持できるからです。「割り当て呼び出しツリー」または「割り当てホットスポット」ビューでガベージコレクションされたオブジェクトを含むモードに生存性セレクタを切り替えると、JProfilerは記録タイプを変更することを提案します。これはプロファイリング設定の変更であるため、変更をすぐに適用することを選択した場合、以前に記録されたすべてのデータがクリアされます。この設定を事前に変更したい場合は、セッション設定ダイアログの「詳細設定」->「メモリプロファイリング」で行うことができます。

次のステップ: ヒープウォーカー

より高度なタイプの質問は、オブジェクト間の参照を含むことになります。たとえば、記録されたオブジェクト、割り当てツリー、および割り当てホットスポットビューに表示されるサイズは浅いサイズです。それらはクラスのメモリレイアウトのみを含み、参照されたクラスは含まれません。クラスのオブジェクトが実際にどれだけ重いかを確認するために、保持サイズ、つまりそれらのオブジェクトがヒープから削除された場合に解放されるメモリ量を知りたいことがよくあります。

この種の情報は、ヒープ上のすべてのオブジェクトを列挙し、高価な計算を行う必要があるため、ライブメモリビューでは利用できません。その作業はヒープウォーカーによって処理されます。ライブメモリビューの興味のあるポイントからヒープウォーカーにジャンプするには、ヒープウォーカーで表示ツールバーボタンを使用できます。それにより、ヒープウォーカーの同等のビューに移動します。

ヒープスナップショットが利用できない場合は、新しいヒープスナップショットが作成されます。それ以外の場合は、JProfilerが既存のヒープスナップショットを使用するかどうかを尋ねます。

いずれにせよ、ライブメモリビューとヒープウォーカーの数値が非常に異なることがよくあることを理解することが重要です。ヒープウォーカーは、ライブメモリビューとは異なる時点でのスナップショットを表示するだけでなく、すべての参照されていないオブジェクトを排除します。ガベージコレクタの状態によっては、参照されていないオブジェクトがヒープのかなりの部分を占めることがあります。