はじめに
前回の記事では、Node.jsのメモリ構造(スタック・ヒープ・V8の世代別ヒープ)を解説しました。
この記事では、前回のヒープ構造の知識を前提に、以下の内容を扱います( ・ᴗ・ )
- ゴミとは何か
- ガベージコレクション(GC)の2種類の仕組み
ガベージコレクションの仕組み
V8のGCは、不要になったオブジェクトのメモリを自動的に回収する仕組みです。
ゴミとは何か
どこからも参照されなくなったオブジェクトをゴミといいます。GCはルート(グローバルオブジェクト・実行スタック)から辿って到達できなかったオブジェクトを回収対象とします。
// 例1: スコープが切れる
function greet() {
const message = { text: 'こんにちは' }; // ヒープに生成
console.log(message.text);
} // 関数終了 → message への参照が切れる → ゴミになる
// 例2: 参照が上書きされる
let user = { name: '田中' };
user = { name: '山田' }; // { name: '田中' } への参照が切れる → ゴミになる
このため、GCが実行されるまでの間、ゴミはヒープに残りメモリを占有し続けます。このゴミを回収する方法として、V8には2種類のGCがあります。
前回の記事で解説したV8のヒープ構造を改めて確認します。
New Space(新世代)のゴミを回収するのが Minor GC、Old Space(旧世代)を中心にヒープ全体を回収するのが Major GC です。
Minor GC(Scavenger)
対象: New Space(新世代)のみ
Scavengerは「コピーGC(semi-space方式)」で動作します。New Spaceは小さく、すぐにオブジェクトで満杯になるため、高頻度でGCが実行されます。
コピー動作の仕組み
New SpaceはFrom-SpaceとTo-Spaceの2つの半分に分かれており、GCが実行されるまでTo-Spaceは常に空の状態を保っています。
GC時にオブジェクトが置かれている側を From-Space、空いている側を To-Space と呼びます。GC時には、From-Spaceの生存オブジェクトをTo-Spaceへコピーします。
以下の図は、GC前後のメモリ状態の変化を示しています。
From-Space の生存オブジェクトだけが To-Space へコピーされ、ゴミはそのまま消えます。コピー後は新しい From-Space(旧 To-Space)の空き領域が次の割り当て先になります。生存オブジェクトが詰め直されることで、断片化も同時に解消されます。
Nursery だった obj_A・obj_E は To-Space へコピーされて Intermediate とみなされます。
一方、すでに Intermediate だった obj_C は 2回目のGCを生き延びたため、To-Space ではなく Old Space へ移動します。
オブジェクトの移動ルート
Minor GC(Scavenger)を生き延びたオブジェクトは、生存回数に応じて行き先が変わります。
以下の図は、オブジェクトがどの経路をたどるかを示しています。
Nursery のオブジェクトが1回目のGCを生き延びると Intermediate とみなされ、さらに2回目のGCも生き延びると Old Space へ移動します。どの段階でも到達不能になったオブジェクトはゴミになり消えます。
Major GC(Mark-Sweep-Compact)
対象: ヒープ全体(主に Old Space)
Old Spaceが一定量まで使われたとき発動する、ヒープ全体を対象とするGCです。3つのフェーズで動作します。
フェーズ1:Marking(マーキング)
GCルート(グローバルオブジェクト・現在の実行スタックなど)から出発して、到達可能なすべてのオブジェクトに印をつける作業です。
印がつかなかったオブジェクトは、どこからも参照されていない、つまりゴミと判断されます。
フェーズ2:Sweeping(スイープ)
Markingで印がつかなかったオブジェクトが占めていたメモリの隙間を、free-list(空きリスト) に登録します。free-listはメモリのサイズ別に管理されており、次にオブジェクトを割り当てる際にfree-listから適切なサイズの空きを探して再利用します。
フェーズ3:Compaction(コンパクション)
ゴミが消えることで生じた小さく散在した隙間を活用するため、生存オブジェクトを別のページにコピーして詰め直す作業です。
なお、Compactionは断片化が激しいページにのみ適用されます。断片化が少ないページにはSweepingのみが行われ、オブジェクトの移動は省略されます。
まとめ
- ゴミ:GCルートから辿れなくなったオブジェクト
- Minor GC:Scavenger。New Spaceをコピー方式で高頻度に掃除
- Major GC:Mark-Sweep-Compact。ヒープ全体を対象に掃除
- Marking:ルートから辿って到達可能なオブジェクトに印をつける
- Sweeping:ゴミが残した隙間をfree-listに登録して再利用
- Compaction:散在した隙間を解消するため生存オブジェクトを詰め直す
参考



