自動メモリ管理は、 マネージド実行中に共通言語ランタイムが提供するサービスの 1 つです。 共通言語ランタイムのガベージ コレクターは、アプリケーションのメモリの割り当てと解放を管理します。 開発者にとっては、マネージド アプリケーションを開発するときにメモリ管理タスクを実行するコードを記述する必要がないことを意味します。 自動メモリ管理により、オブジェクトの解放を忘れたり、メモリ リークの原因になったり、既に解放されているオブジェクトのメモリにアクセスしようとしたりするなどの一般的な問題を排除できます。 このセクションでは、ガベージ コレクターがメモリを割り当てて解放する方法について説明します。
メモリの割り当て
新しいプロセスが初期化されると、ランタイムは連続したアドレス空間領域をそのプロセスのために予約します。 この予約済みのアドレス空間をマネージド ヒープと呼びます。 マネージド ヒープは、ヒープ内で次のオブジェクトを割り当てるアドレスへのポインターを管理します。 初期状態では、このポインターはマネージド ヒープのベース アドレスに設定されます。 すべての 参照型 は、マネージド ヒープに割り当てられます。 アプリケーションが最初の参照型を作成すると、マネージド ヒープのベース アドレスの位置にその型のメモリが割り当てられます。 アプリケーションが次のオブジェクトを作成すると、ガベージ コレクターは最初のオブジェクトの直後のアドレス空間にメモリを割り当てます。 アドレス空間が使用可能な限り、ガベージ コレクターは、この方法で新しいオブジェクトの領域を割り当て続けます。
マネージド ヒープからのメモリ割り当ては、アンマネージド メモリ割り当てよりも高速に処理されます。 ランタイムはポインターに値を追加してオブジェクトにメモリを割り当てるので、スタックからメモリを割り当てるのとほぼ同じ速度です。 また、連続して割り当てられる新しいオブジェクトはマネージド ヒープに連続して格納されるため、アプリケーションはオブジェクトに非常に迅速にアクセスできます。
メモリの解放
ガベージ コレクターの最適化エンジンは、現在の割り当て状況に基づいて、ガベージ コレクションの実行に最適な時期を判断します。 ガベージ コレクターは、ガベージ コレクションを実行するときに、アプリケーションが使用しなくなったオブジェクトのメモリを解放します。 アプリケーションのルートを調べることで、使用されなくなったオブジェクトを決定します。 すべてのアプリケーションには、一連のルートがあります。 各ルートは、マネージド ヒープ上のオブジェクトを参照しているか、または null に設定されています。 アプリケーションのルートには、静的フィールド、スレッドのスタック上のローカル変数とパラメーター、CPU レジスタが含まれます。 ガベージ コレクターは、 Just-In-Time (JIT) コンパイラ とランタイムが保持するアクティブなルートの一覧にアクセスできます。 このリストを使用して、アプリケーションのルートを調べ、プロセスでルートから到達可能なすべてのオブジェクトを含むグラフを作成します。
グラフに含まれていないオブジェクトは、アプリケーションのルートから到達できません。 ガベージ コレクターは、到達できないオブジェクトのガベージを考慮し、割り当てられたメモリを解放します。 ガベージ コレクション中に、ガベージ コレクターはマネージド ヒープを調べ、到達できないオブジェクトが占有しているアドレス空間ブロックを検索します。 到達できないオブジェクトを検出すると、それらのオブジェクトに割り当てられていたアドレス空間ブロックを解放し、メモリ コピー機能を使用して、到達できるオブジェクトのメモリを圧縮します。 到達できるオブジェクトのメモリを圧縮した後で、ガベージ コレクターは、アプリケーションのルートがそれらのオブジェクトの新しい位置を指すようにポインターを修正します。 また、マネージド ヒープのポインターも、最後の到達できるオブジェクトの後を指すように修正します。 メモリは、コレクションが多数の到達不能オブジェクトを検出した場合にのみ圧縮されることに注意してください。 マネージド ヒープ内のすべてのオブジェクトがコレクションに残っている場合、メモリ圧縮は必要ありません。
パフォーマンスを向上させるために、ランタイムは、大きいオブジェクトのメモリは独立したヒープに割り当てます。 ガベージ コレクターは、これらの大きいオブジェクトのメモリを自動的に解放します。 ただし、メモリ内の大きなオブジェクトの移動を回避するために、このメモリは圧縮されません。
世代とパフォーマンス
ガベージ コレクターのパフォーマンスを最適化するために、マネージド ヒープは 0、1、2 の 3 つの世代に分けられます。 ランタイムのガベージ コレクション アルゴリズムは、コンピューター ソフトウェア業界がガベージ コレクション スキームを試して真であると検出したいくつかの一般化に基づいています。 まず、マネージド ヒープ全体よりも、マネージド ヒープの一部のメモリを圧縮する方が高速です。 第 2 に、新しいオブジェクトの有効期間が短くなり、古いオブジェクトの有効期間が長くなります。 最後に、新しいオブジェクトは互いに関連し、アプリケーションによって同時期にアクセスされる傾向があります。
ランタイムのガベージ コレクターは、新しいオブジェクトをジェネレーション 0 に格納します。 アプリケーションの有効期間の初期に作成され、ガベージ コレクションでごみではないと判断されたオブジェクトは昇格してジェネレーション 1 とジェネレーション 2 に格納されます。 オブジェクトの昇格のプロセスについては、このトピックの後半で説明します。 ヒープ全体よりもマネージド ヒープの一部を圧縮する方が高速であるため、このスキームにより、ガベージ コレクターはコレクションを実行するたびにマネージド ヒープ全体のメモリを解放するのではなく、特定の世代でメモリを解放できます。
実際には、ジェネレーション 0 がいっぱいになると、ガベージ コレクターによってコレクションが実行されます。 ジェネレーション 0 がいっぱいのときにアプリケーションが新しいオブジェクトを作成しようとすると、ガベージ コレクターは、オブジェクトに割り当てるアドレス空間がジェネレーション 0 に残っていないことを検出します。 ガベージ コレクターは、オブジェクトのジェネレーション 0 のアドレス空間を解放しようとしてコレクションを実行します。 まず、ガベージ コレクターは、マネージド ヒープ内の全オブジェクトではなく、ジェネレーション 0 のオブジェクトだけを調べます。 これは、新しいオブジェクトの有効期間が短くなる傾向があり、ジェネレーション 0 のオブジェクトの多くがコレクションの実行時にアプリケーションで使用されなくなることが予想されるため、最も効率的な方法です。 さらに、多くの場合、ジェネレーション 0 のコレクションだけでは、アプリケーションが新しいオブジェクトを作成し続けるのに十分なメモリが再利用されます。
ガベージ コレクターは、ジェネレーション 0 のコレクションを実行した後、このトピックの「メモリの解放」で説明したように、到達可能なオブジェクトの メモリを 圧縮します。 その後、ガベージ コレクターはこれらのオブジェクトを昇格させ、マネージド ヒープジェネレーション 1 のこの部分を考慮します。 一般にガベージ コレクションでごみだと判断されなかったオブジェクトの存続期間は長いので、これらのオブジェクトを上位のジェネレーションに昇格させるのは有効です。 その結果、ガベージ コレクターは、ジェネレーション 0 のコレクションを実行するたびに、ジェネレーション 1 とジェネレーション 2 のオブジェクトを再検討する必要はありません。
ガベージ コレクターは、ジェネレーション 0 の最初のコレクションを実行し、到達可能なオブジェクトをジェネレーション 1 に昇格した後、マネージド ヒープ世代 0 の残りの部分を考慮します。 ジェネレーション 0 がいっぱいになり、別のコレクションを実行する必要があるまで、ジェネレーション 0 の新しいオブジェクトにメモリを割り当て続けます。 この時点で、ガベージ コレクターの最適化エンジンは、古い世代のオブジェクトを調べる必要があるかどうかを判断します。 たとえば、ジェネレーション 0 のコレクションが、アプリケーションが新しいオブジェクトの作成を正常に完了するのに十分なメモリを解放できない場合、ガベージ コレクターはジェネレーション 1 のコレクションを実行してから、ジェネレーション 2 を実行できます。 これで十分なメモリが解放されない場合、ガベージ コレクターはジェネレーション 2、1、0 のコレクションを実行できます。 各コレクションの後、ガベージ コレクターは、ジェネレーション 0 で到達可能なオブジェクトを圧縮し、それらをジェネレーション 1 に昇格します。 ガベージ コレクションでごみだと判断されなかったジェネレーション 1 のオブジェクトは、ジェネレーション 2 に昇格します。 ガベージ コレクターは 3 つの世代しかサポートしていないため、ジェネレーション 2 のオブジェクトは、後のコレクションで到達できないと判断されるまで、ジェネレーション 2 に残ります。
アンマネージ リソースのメモリの解放
アプリケーションが作成するオブジェクトの大部分では、ガベージ コレクターを使用して、必要なメモリ管理タスクを自動的に実行できます。 しかし、アンマネージ リソースでは、明示的なクリーンアップが必要です。 最も一般的な種類のアンマネージ リソースは、ファイル ハンドル、ウィンドウ ハンドル、ネットワーク接続などのオペレーティング システム リソースをラップしたオブジェクトです。 ガベージ コレクターは、アンマネージ リソースをカプセル化するマネージド オブジェクトの有効期間を追跡できますが、リソースのクリーンアップ方法に関する特定の知識はありません。 アンマネージ リソースをカプセル化するオブジェクトを作成するときは、パブリック Dispose メソッドでアンマネージ リソースをクリーンアップするために必要なコードを指定することをお勧めします。 Dispose メソッドを指定すると、オブジェクトのユーザーがオブジェクトの終了時にメモリを明示的に解放できるようになります。 アンマネージ リソースをカプセル化するオブジェクトを使用する場合は、 Dispose を認識し、必要に応じて呼び出す必要があります。 アンマネージ リソースのクリーンアップと Dispose を実装するための設計パターンの例の詳細については、「 ガベージ コレクション」を参照してください。
こちらも参照ください
.NET