dotMemory 2025.3 ヘルプ

GC ルートの分析

オブジェクトの保持パスは常に GC ルートで始まります。ガベージコレクターの観点から見ると、ルートは、収集してはいけない、または収集されないオブジェクトへの参照です。これにより、ルートが保持グラフを構築するための唯一の可能な開始点になります。ルートタイプを理解することは、「誰がオブジェクトを保持するか ? 」を検討する際に不可欠となる場合があります。分析。保持パスを調べても、オブジェクトがまだメモリ内にある理由がわからない場合があります。この場合、GC ルートを調べることは理にかなっています。例: RefCounted ハンドルは、アンマネージ COM ライブラリがオブジェクトを保持していることを示します。

.NET には 4 つのルートタイプがあります。

  • スタック参照 : ローカルオブジェクトへの参照。このようなルートはメソッドの実行中に存続します。

  • 静的参照 : 静的オブジェクトへの参照。これらのルートは、アプリドメインの存続期間全体にわたって存続します。

  • ハンドル : 通常、これらは管理対象コードと管理対象外コード間の通信に使用される参照です。そのようなルートは、少なくともアンマネージコードが「管理された」オブジェクトを必要とするまで存続しなければなりません。

  • ファイナライザの参照 : ファイナライズされるのを待っているオブジェクトへの参照。これらのルートはファイナライザが実行されるまで生き続けます。

保持パスのルートを分析するには、オブジェクト保持パスを表示するビュー ( 同様の保持キー保持パスルートへの最短経路 ) を使用します。dotMemory で区別されるすべてのルートタイプは、上記のリストに記載されているカテゴリのいずれかに分類されることに注意してください。

通常のローカル変数

メソッド内で宣言されたローカル変数(スタック上の変数)です。この変数への参照は、メソッドの存続期間中はルートになります。例:

static void Main() { ... var collection = new Collection <int>(); ... }
Regular local variable root

リリースビルドでは、root の有効期間が短くなる可能性があることに注意してください。JIT は、変数が不要になった直後に変数を破棄することができます。

静的リファレンス

CLR は、静的オブジェクト (クラスメンバー、変数、イベント) に遭遇すると、このオブジェクトのグローバルインスタンスを作成します。オブジェクトはアプリの有効期間中ずっとアクセスできるため、静的オブジェクトが収集されることはほとんどありません。静的オブジェクトへの参照は、主要なルート型の 1 つです。

class SomeClass { public static Collection<string> StCollection; }

コレクションが初期化された後、CLR はコレクションの静的インスタンスを作成します。インスタンスへの参照は、アプリケーションドメインの有効期間中に存在します。

Static reference root

静的オブジェクトがフィールドを介して参照されると、dotMemory はフィールドの名前を表示します。

F 到達可能キュー / ファイナライズキュー

CLR は、アンマネージリソースを解放するための便利なメカニズム、ファイナライズパターンを提供します。System.Object 型は、オブジェクトのメモリが再利用される前にガベージコレクターによって呼び出される仮想メソッド Finalize (ファイナライザーとも呼ばれます) を宣言します。通常、このメソッドをオーバーライドしてアンマネージリソースを解放します。ファイナライザーを持つオブジェクトはすべて、ファイナライズキューに入れられます (dotMemory では、これらのオブジェクトのルートはファイナライズキューです)。ガベージコレクションが行われると、GC はファイナライズキューでそのようなオブジェクトを見つけますが、ファイナライザーを直接実行しません。代わりに、GC はオブジェクトを F 到達可能キュー (dotMemory では F 到達可能キュールート) に入れ、ファイナライザーを別のファイナライズスレッドで実行します (ファイナライザーは任意の量のコードを実行できるため、これはパフォーマンスのために行われます)。次の GC では、F 到達可能キューのオブジェクトがガベージコレクションされます。説明したパターンには欠点があるため、dotMemory では特別なファイナライズ可能オブジェクトインスペクションが提供されています。

メモリプロファイリングの性質上、dotMemory はスナップショットを取得する前に必ずフル GC を実行します。そのため、dotMemory で取得したスナップショットにはファイナライズキュールートのオブジェクトは見つかりません。このルートタイプは、生のメモリダンプでのみ可能です。

F-Queue root

ピンニングハンドル

マネージコードとアンマネージコードの相互作用は、ガベージコレクターにとって追加の問題です。例: マネージヒープから外部 API ライブラリなどにオブジェクトを渡す必要があるとします。コレクション中に小さなオブジェクトヒープが圧縮されると、オブジェクトが移動される可能性があります。これは、正確なオブジェクトの位置に依存するアンマネージコードにとって問題となります。解決策の 1 つは、ヒープ内のオブジェクトを固定することです。この場合、GC はオブジェクトへの固定ハンドルを取得します。これは、オブジェクトを移動できないことを意味します (固定オブジェクト)。ピンニングハンドルルートが表示された場合、おそらくオブジェクトは何らかのアンマネージコードによって保持されています。たとえば、App オブジェクトには常に固定参照があります。

Pinning handle root

スナップショットにピンニングハンドルが表示される場合があります。場合によっては、静的参照を正しく識別できないことがあります。静的リファレンスルートの代わりに、ピンニングハンドルルートによって保持されているオブジェクト Object[] の配列が表示されることがあります。これは、静的参照がどのように機能するかの真の表現です。

Pinning handle root instead of a static reference root

dotMemory を使用すると、スナップショット内のすべての固定オブジェクトを個別のオブジェクトセットとして開くことができます。これを行うには、インスペクションビューを開き、ヒープフラグメンテーションセクションでピン留めオブジェクトのリンクをクリックします。

Pinned objects

内部ローカル変数

管理対象オブジェクトはガベージコレクション中に移動される可能性があるため ( ピンニングハンドルを参照)、ネイティブポインターを使用してヒープ上の位置を追跡することはできません。このような場合は、内部ポインターを使用できます。内部ポインターは、参照型の内部へのポインターを宣言しますが、オブジェクト自体へのポインターを宣言しません。オブジェクトを保持する内部ローカル変数ルートが表示されている場合は、このオブジェクトの内部を指す内部ポインターが存在する可能性があります。例については、マイクロソフトラーンを参照してください。

Interior local variable

RefCounted ハンドル

ルートは、オブジェクトの参照カウントが特定の値である場合、ガベージコレクションを防止します。COM 相互運用機能を使用してオブジェクトが COM ライブラリに渡される場合、CLR はこのオブジェクトへの RefCounted ハンドルを作成します。COM はガベージコレクションを実行できないため、このルートが必要になります。代わりに、参照カウントを使用します。オブジェクトが不要になった場合、COM はカウントを 0 に設定します。これは、RefCounted ハンドルがルートではなくなり、オブジェクトを収集できることを意味します。

RefCounted ハンドルと表示された場合、おそらく、オブジェクトはアンマネージコードの引数として渡されます。

RefCounted handle root

弱いハンドル

他のルートとは異なり、弱いハンドルは参照されたオブジェクトのガベージコレクションを妨げません。オブジェクトはいつでも収集できますが、アプリケーションからアクセスできます。このようなオブジェクトへのアクセスは、WeakReference タイプの中間オブジェクトを介して実行されます。このようなアプローチは、キャッシュなどの一時的なデータ構造を操作する場合に効率的です。弱い参照は完全なガベージコレクションを生き残れないため、弱い参照ハンドルは他のハンドルと組み合わせてのみ使用できます。例: 弱い、RefCounted ハンドル

Weak handle root

レギュラーハンドル

ハンドルタイプが未定義の場合、dotMemory はそれをレギュラーハンドルとしてマークします。通常、これらはアプリの存続期間中に必要なシステムオブジェクトへの参照です。例: OutOfMemoryException オブジェクト。コレクションを防ぐために、環境は通常のハンドルを通じてオブジェクトを参照します。

Regular handle root
2024 年 7 月 24 日

関連ページ:

同様の保持

同様の保持ビューは、オブジェクトを保持パスの類似性によってグループ化します。各オブジェクトセットについて、ビューにはルートへの 2 つの最短パスが表示されます。dotMemory は、さまざまな最短パスの中から、互いに最も異なる 2 つのパスのみを選択することに注意してください。同様の保持ビューを使用すると、同じ型のオブジェクトが論理的にどこに属しているかを区別できます。例: 配列内の複数の変数は同じ保持パスを持ちますが、これは他の配列の変数とは異なります。同様の保持を使用して、オブジェクトがま...

キー保持パス

キー保持パスビューでは、オブジェクトインスタンスの主要な保持パスを確認できます。具体的には、互いに最も大きく異なるパスのみが表示されます。最短の保持パスに重点を置く他の保持ビューとは異なり、このビューでは、考えられるすべての保持の組み合わせで圧倒されることなく、最も重要で明確な保持パスがハイライトされます。例: オブジェクト D のキー保持パスビューには、A> B> D と E> F> G> D の 2 つのパスのみが含まれます。パス A> C> D は A> B&...

ルートへの最短経路

ルートへの最短経路ビューグループは、アプリケーションのルートからインスタンスへの最短パス (各ルートの最短パス) を表示します。便宜上、dotMemory は、プレーンリスト(最短パス)とツリー(結合された最短経路)の 2 通りの方法でパスを表示します。特定の方法を選択するには、ビューのリストで対応するボタンをクリックします。ビューを使用してインスタンスの保存パスをインスペクションし、インスタンスの収集を妨げている原因を特定します。これは、排他的に保持されていないオブジェクトを調査する場合に役立...

自動インスペクション

dotMemory はスナップショットを自動的に分析し、多くのメモリの問題を検出できます。文字列重複:既存のものを再利用するのではなく、同じ値を持つ文字列を繰り返し作成することは、メモリを無駄にします。dotMemory は重複した文字列を検出し、無駄なメモリ量を示します。オブジェクトを分析するにはインスペクションヘッダーのリンクをクリックするか、リスト内の特定のオブジェクトセットをダブルクリックします。問題を解決するには同じ値を持つ文字列が大量のメモリを浪費したり、大量のトラフィックを生成し...

クロスワークスペースの比較ビュー

クロスワークスペース比較は、異なるワークスペースに保存されているスナップショット (つまり、異なるプロファイリングセッションで収集されたスナップショット) を比較することです。dotMemory は異なるプロファイリングセッションのオブジェクトの有効期間を一致させることができないため、クロスワークスペースの比較ビューには新しいオブジェクトまたは収集されたオブジェクトのデータは表示されません。既存のオブジェクト (ガベージコレクションを生き残ったオブジェクト) のみがタイプ別に一致します。クロスワ...