ガベージコレクション
不要になったメモリを自動的に解放するランタイムの仕組み
メモリ管理ランタイム
ガベージコレクションとは
ガベージコレクション (GC) は、プログラムが使わなくなったメモリを自動的に検出・解放するランタイムの仕組みである。JavaScript (V8)、Java (JVM)、Go、Python が GC を持つ。Rust は GC の代わりに所有権システムでメモリを管理する。
GC あり vs GC なし
| 観点 | GC あり (JS, Java, Go) | GC なし (Rust, C) |
|---|---|---|
| メモリ管理 | 自動 | 手動 (Rust は所有権) |
| メモリリーク | 起きにくい | 起きやすい (C) |
| パフォーマンス | GC 停止 (STW) がある | 予測可能 |
| 開発速度 | 速い | 遅い (メモリを意識) |
V8 (Node.js) の GC
V8 は世代別 GC を採用している。
Young Generation (新世代):
新しいオブジェクトを格納
頻繁に GC (Scavenge) → 生き残ったオブジェクトは Old へ
Old Generation (旧世代):
長寿命のオブジェクトを格納
低頻度で GC (Mark-Sweep-Compact)
| 世代 | GC アルゴリズム | 頻度 | 停止時間 |
|---|---|---|---|
| Young | Scavenge (コピー GC) | 高い | 短い (1〜10ms) |
| Old | Mark-Sweep-Compact | 低い | 長い (10〜100ms) |
メモリリーク
GC があってもメモリリークは発生する。参照が残っている限り GC は回収しない。
// ❌ メモリリーク: イベントリスナーの解除忘れ
element.addEventListener('click', handler);
// element が削除されても handler が参照を保持 → GC されない
// ❌ メモリリーク: クロージャが大きなオブジェクトを保持
function createHandler() {
const largeData = new Array(1000000); // 100万要素
return () => console.log(largeData.length); // largeData への参照が残る
}
// ❌ メモリリーク: グローバル変数にデータを蓄積
const cache: Record<string, any> = {};
function addToCache(key: string, value: any) {
cache[key] = value; // 際限なく増加
}
Lambda でのメモリ管理
Lambda の MemorySize 設定は GC の挙動に影響する。メモリが少ないと GC が頻繁に発生し、レイテンシが増加する。
メモリリークの検出
# Node.js のヒープスナップショット
node --inspect app.js
# Chrome DevTools → Memory → Heap Snapshot
Rust の所有権 (GC の代替)
{
let s = String::from("hello"); // s がメモリを所有
// s を使用
} // スコープを抜けると自動的にメモリ解放 (GC 不要)
理論と実装の両面から学ぶなら関連書籍が参考になる。