GC ルートの分析
オブジェクトの保持パスは常に GC ルートから始まります。 ガベージコレクターから見ると、ルートは収集されてはいけない、また収集されることのないオブジェクトへの参照です。 これにより、保持グラフを構築する際の唯一の開始点となります。 ルートタイプを理解することは、「誰がオブジェクトを保持しているのか?」を分析する際に重要になる場合があります。 時には保持パスを調べても、なぜオブジェクトがメモリに残っているのか分からないこともあります。 この場合は、GC ルートを見るのが有効です。 例えば、 RefCounted ハンドルは、一部の非管理 COM ライブラリがオブジェクトを保持していることを示します。
.NET には 4 つのルートタイプがあります。
スタック参照: ローカルオブジェクトへの参照。 このようなルートはメソッドの実行中に存続します。
静的参照: 静的オブジェクトへの参照。 これらのルートは、アプリドメインの存続期間全体にわたって存続します。
ハンドル: 通常、これらは管理対象コードと管理対象外コード間の通信に使用される参照です。 そのようなルートは、少なくともアンマネージコードが「管理された」オブジェクトを必要とするまで存続しなければなりません。
ファイナライザの参照: ファイナライズされるのを待っているオブジェクトへの参照。 これらのルートはファイナライザが実行されるまで生き続けます。
保持パスのルートを分析するには、オブジェクト保持パスを表示するビュー (同様の保持力、 キー保持パス、 ルートへの最短パス) を使用します。 dotMemory で区別されるすべてのルートタイプは、上記のリストに記載されているカテゴリのいずれかに分類されることに注意してください。
通常のローカル変数
メソッド内で宣言されたローカル変数(スタック上の変数)です。 この変数への参照は、メソッドの存続期間中はルートになります。 例えば:

リリースビルドでは、ルートの寿命が短くなる場合があることに注意してください。JIT は必要がなくなった変数をすぐに破棄することがあります。
静的リファレンス
CLR は、静的オブジェクト (クラスメンバー、変数、イベント) に遭遇すると、このオブジェクトのグローバルインスタンスを作成します。 オブジェクトはアプリの有効期間中ずっとアクセスできるため、静的オブジェクトが収集されることはほとんどありません。 静的オブジェクトへの参照は、主要なルート型の 1 つです。
コレクションが初期化された後、CLR はコレクションの静的インスタンスを作成します。 インスタンスへの参照は、アプリケーションドメインの有効期間中に存在します。

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

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

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

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

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

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

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

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