ガベージコレクション — 辿れないものはゴミ
プログラムが作ったオブジェクトは、使い終わったら片付けないとメモリがどんどん埋まっていきます。でも「もう使わない」と人間が毎回宣言するのは面倒だし、消し忘れるとメモリリーク、まだ使うものを消すとクラッシュ。そこで多くの言語は、不要なオブジェクトを自動で回収する仕組み=ガベージコレクション(GC)を持っています。
では、GCはどうやって「もう使わない」を見分けるのでしょう? 答えは「ルートからたどり着けるか」だけ。たどり着けるものは生存、たどり着けないものはゴミ。下の図1で参照の線(✂のついた線)を切って、辿れなくなったオブジェクトがマーク&スイープで回収される様子を見てください。
「使うか」ではなく「辿れるか」で決める
GCは、オブジェクトが将来本当に使われるかは分かりません。代わりに「いま、ルート(実行中の変数やグローバル)から参照をたどって到達できるか」という、機械的に判定できる基準を使います。到達できなくなった瞬間、そのオブジェクトは二度と使えない=ゴミだと確定するからです。
マーク&スイープはこれを2段階で行います。マーク=ルートから参照をたどり、届いた全部に「生存」の印をつける。スイープ=ヒープ全体を見回り、印のないものを回収する。この方式の強みは、循環参照(AとBが互いを参照し合う)でも、ルートから辿れなければちゃんと回収できること。単純な参照カウント方式が苦手とするケースを正しく片付けられます。
- ルート
- たどり始めの起点。実行中のスタック上の変数やグローバル変数など。
- 到達可能性
- ルートから参照をたどって届けるか。届かないオブジェクトがゴミ。
- 参照カウント
- 参照された数を数える別方式。手軽だが循環参照を回収できない弱点がある。
まとめ
ガベージコレクションは「片付け忘れ」をなくす代わりに、回収のタイミングで処理が一瞬止まる(GCポーズ)などのコストを払っています。だからこそ、不要になった参照は早めに手放す(変数にnullを入れる、スコープを小さく保つ)ことが、メモリを無駄に抱え込まないコツになります。GCの判断基準が「辿れるかどうか」だと分かっていれば、なぜ参照を切ることが大事なのかも腑に落ちるはずです。