.NET の高度なコンテンツの一部として、ガベージ コレクター (略して GC) を理解する必要があります。この記事では、「分かりやすさ」の原則に従って、CLR のガベージ コレクターの動作原理を説明します。
基礎知識
マネージドヒープ
まずMSDNの説明を見てみましょう: 新しいプロセスを初期化するとき、ランタイムはプロセス用に連続したアドレス空間領域を予約します。この予約されたアドレス空間はマネージド ヒープと呼ばれます。
「マネージド ヒープもヒープです」、なぜそう言うのですか?この知識の前提は「値型と参照型の違い」です。ここでは、読者は「値型はスタックに格納され、参照型はヒープに格納される(参照型の参照はスタックに格納される)」という重要な概念をすでに知っているものとします。したがって、この理論によれば、CLR では、値型を除くすべてのリソースがマネージド ヒープから割り当てられる必要があります。
マネージド ヒープは、ヒープ内の次のオブジェクトの割り当て場所を指す、ここでは NextObjPtr という名前のポインターを保持します。
CPU レジスタ
これは、以下の「根本的な」概念を理解するためにここで復習してください。
CPU レジスタは CPU 自体の「一時メモリ」であり、メモリアクセスよりも高速です。 CPU からの距離が近い順に、レジスタ、次にキャッシュ (コンピュータのレベル 1、レベル 2、およびレベル 3 キャッシュ)、最後にメモリです。
ルート
クラスで定義された静的フィールド、メソッドパラメータ、ローカル変数(参照型変数のみ)などはルートです。また、CPUレジスタ内のオブジェクトポインタもルートです。ルートは、CLR がヒープの外で見つけることができるさまざまなエントリ ポイントです。
到達可能なオブジェクトと到達不可能なオブジェクト
ルートがヒープ内のオブジェクトを参照している場合、そのオブジェクトは「到達可能」であり、それ以外の場合は「到達不能」です。
ガベージコレクションの理由
コンピュータの構成の観点から見ると、すべてのプログラムはメモリ上に常駐して実行する必要があります。そしてメモリは制限要因 (サイズ) です。これに加えて、マネージド ヒープにはサイズ制限もあります。マネージド ヒープにサイズ制限がない場合、C# の実行速度は c の実行速度よりも向上します (マネージド ヒープの構造により、C ランタイム ヒープよりも速くオブジェクトを割り当てることができます)。アドレス空間とストレージの制限により、マネージド ヒープはガベージ コレクション メカニズムを通じて通常の動作を維持し、オブジェクトが「メモリ オーバーフロー」なく割り当てられるようにする必要があります。
ガベージ コレクションの基本原則
リサイクルは 2 つの段階に分かれています: マーキング –> 圧縮
マーキングのプロセスは、実際には、オブジェクトが到達可能かどうかを判断するプロセスです。すべてのルートがチェックされると、ヒープには到達可能な (マークされた) オブジェクトと到達不可能な (マークされていない) オブジェクトが含まれます。
マーキングが完了したら、圧縮段階に入ります。このフェーズでは、ガベージ コレクターはヒープを線形に走査して、到達不能なオブジェクトの連続したメモリ ブロックを見つけます。そして、ヒープを圧縮するために、到達可能なオブジェクトをここに移動します。このプロセスは、ディスク領域のデフラグに似ています。
上の図に示すように、緑色のボックスは到達可能なオブジェクトを示し、黄色のボックスは到達不可能なオブジェクトを示します。到達不可能なオブジェクトが削除された後、到達可能なオブジェクトを移動すると、メモリの圧縮が実現します (よりコンパクトになります)。
圧縮後、変数と CPU レジスタの「これらのオブジェクトへのポインタ」は無効になり、ガベージ コレクターはすべてのルートを再訪し、オブジェクトの新しいメモリ位置を指すようにルートを変更する必要があります。これにより、パフォーマンスが大幅に低下する可能性があります。この損失は、マネージド ヒープの主な欠点でもあります。
上記の特徴を踏まえ、ガベージコレクションによるリサイクルアルゴリズムも研究課題となっています。マネージド ヒープがいっぱいになるまで待ってからガベージ コレクションを開始すると、処理が非常に「遅く」なるからです。
ガベージ コレクション アルゴリズム - 生成アルゴリズム
生成は、CLR ガベージ コレクターによって使用されるメカニズムです。その唯一の目的は、アプリケーションのパフォーマンスを向上させることです。世代別リサイクルは、ヒープ全体をリサイクルするよりも明らかに高速です。
CLR マネージド ヒープは、第 0 世代、第 1 世代、第 2 世代の 3 世代をサポートします。世代 0 の容量は約 256KB、世代 1 は約 2M、世代 2 は約 10M です。新しく構築されたオブジェクトは世代 0 に割り当てられます。上の図に示すように、世代 0 のスペースがいっぱいになると、ガベージ コレクターがリサイクルを開始し、到達できないオブジェクト (上の図の C と E) がリサイクルされます。生き残ったオブジェクトは第 1 世代として分類されます。
第 0 世代のスペースがいっぱいになり、第 1 世代にも到達できないオブジェクトが多くなり始め、スペースがほぼいっぱいになると、両方の世代のゴミがリサイクルされます。存続するオブジェクト (到達可能なオブジェクト) の場合、世代 0 は世代 1 に昇格し、世代 1 は世代 2 に昇格します。
実際の CLR 世代のコレクション メカニズムは、より「インテリジェント」です。新しく作成されたオブジェクトのライフサイクルが短い場合、第 0 世代のガベージはガベージ コレクターによって (スペースが完全に割り当てられるのを待たずに) すぐにリサイクルされます。さらに、世代 0 がリサイクルされ、「到達可能な」オブジェクトがまだ多くあり、
があまりメモリを解放していないことが判明した場合、世代 0 のバジェットは 512KB に増加し、リサイクル効果は次のように変換されます。ガベージ コレクションの数は減りますが、毎回大量のメモリが再利用されます。メモリがあまり解放されていない場合、ガベージ コレクターは フル コレクション (3 世代) を実行します。それでも十分ではない場合は、「メモリ オーバーフロー」例外がスローされます。 言い換えれば、ガベージ コレクターは、回復されたメモリのサイズに基づいて、各世代の割り当てられたスペース バジェットを動的に調整します。自動最適化を実現! まとめ ガベージ コレクションの背後には基本的な考え方があります。つまり、プログラミング言語 (ほとんどの言語) は常に無制限のメモリにアクセスできるように見えます。そして開発者は、魔法のように、無尽蔵に割り当て、割り当て、割り当てを続けることができます。 .NET ガベージ コレクターの基本的な動作原理は、最も基本的なマークと明確な原理によって到達不能なオブジェクトをクリアし、次にディスクのデフラグのように利用可能なメモリを圧縮して整理し、最後に世代別アルゴリズムによってパフォーマンスを最適化します。