ガーベッジコレクションとは(全体像)
GCは、もう使わないメモリを、プログラムに代わって自動で片付けてくれるしくみのこと。手動で「確保したら必ず解放する」のは間違えやすいので、これを自動化して取りこぼしを防ぐ。
身近にたとえると、オフィスの清掃だ。使っている机に印をつけて、印のない机を片付ける(マーク&スイープ)、新入社員のエリアだけ毎日掃除する(世代別)、というように、片付け方にいくつか流派がある。
押さえるのは、GCは便利だが「片付けの間、作業がいったん止まる時間」があること。これをSTW(Stop The World)という。
詳しく:アルゴリズムとSTWだけ覚えれば戦える
ここが記事の心臓部。まず代表的なGCの方法を見ましょう。
代表的なGCの方法
| 方法 | 考え方 | 特徴 |
|---|---|---|
| マーク&スイープ | 使われているものに印 → 印なしを回収 | 基本。すき間(断片化)が出る |
| コピーGC | 生きているものを別領域へコピー | すき間なし。メモリを2倍使う |
| 世代別GC | 新しいものはすぐ死ぬ前提で分ける | 効率がよい。Javaの主流 |
| 参照カウント | 使われている数を数える | 0で回収。循環参照に弱い |
マーク&スイープは、使われているメモリに印をつけ、印のないものを回収する基本の方法です。世代別GCは、「新しいオブジェクトはすぐ使われなくなる」という経験をいかし、新しいものの置き場(Young)を頻繁に、長生きするものの置き場(Old)をたまに片付けて、効率を上げます。
参照カウントは、それぞれのメモリが何か所から使われているかを数え、0になったら回収する方法(Pythonなど)ですが、お互いに参照し合う「循環参照」に弱いという弱点があります。
ここで一番のひっかけが「GCは常に高速で止まらない」という誤解。GCの片付け中はプログラムがいったん止まる時間(STW)があります。最近の並行GC(G1・ZGCなど)でこの止まる時間は大きく短くなりましたが、ゼロではありません。
最後に、GCを使わない言語もあります。
GCを使う言語・使わない言語
| 区分 | 言語 |
|---|---|
| GCを使う | Java・Python・Go・C#など |
| GCを使わない | C・C++(手動)・Rust(所有権で自動管理) |
2つめのひっかけが「RustはGCを使う」という誤解。Rustは所有権というしくみで、GCを使わずにメモリを管理します。
わかりやすく言い換えると
要するに、オフィス清掃のたとえで覚えるとラクです。
①GCの方法 … マーク&スイープ(印をつけて片付け)、世代別(新しいエリアを頻繁に)、参照カウント(使われている数を数える)
②STW … 片付けの間は作業が止まる(常に高速ではない・並行GCで短縮)
③RustはGCなし … 所有権でメモリを管理する(GCを使わない)
つまり、「GCにはSTW(止まる時間)がある」「RustはGCを使わない」、この2点が試験の急所です。
試験のツボ
🔴 一番出る:GCとSTW
①GC = 使い終わったメモリを自動で回収(メモリリークを防ぐ)
②STW = 片付け中はプログラムが止まる(常に高速ではない・並行GCで短縮)
🔴 次に出る:代表的な方法
①マーク&スイープ(印をつけて回収)/世代別GC(新しいものはすぐ死ぬ前提)
②参照カウント(使われる数を数える・循環参照に弱い)
🟡 押さえると安定:GCなしの言語
①RustはGCを使わず、所有権でメモリを管理する
②C・C++は手動でメモリを確保・解放する
よくある間違い
①「GCは常に高速で、止まる時間はない」→ ✗ GCの片付け中はプログラムが止まる時間(STW)がある。並行GCで短くなるがゼロではない。
②「RustはGCを使ってメモリを管理する」→ ✗ Rustは所有権というしくみで、GCを使わずにメモリを管理する。
③「参照カウントは循環参照も問題なく回収できる」→ ✗ 参照カウントはお互いに参照し合う循環参照に弱く、別のしくみ(サイクル検出など)が必要。
試験での出題パターン
実際の問題でたしかめてみよう。
オリジナル問題1(GCとSTW)
ガーベッジコレクションに関する次の記述のうち、正しいものはどれか。
- GCは常に高速でいっさい止まらず、片付け中に処理が止まることはないものだとされている
- GCは紙に印刷する装置のことで、メモリの回収とは無関係なものだとされているものだ
- GCはメモリを必ず増やし続ける機能で、使い終わったメモリは回収しないものだとされている
- GCは使い終わったメモリを自動で回収するが、片付け中に止まる時間(STW)がある
解答は 4 ですよ。
GCは使い終わったメモリを自動で回収するしくみですが、片付け中に止まる時間(STW)がありますね。常に高速というわけではありません。
選択肢1の「いっさい止まらない」、選択肢2の「印刷する装置」、選択肢3の「増やし続ける」はどれも誤りですよ。
| 選択肢 | 判定 | 理由 |
|---|---|---|
| 1 | ✗ | 止まる時間(STW)がある |
| 2 | ✗ | 印刷する装置ではない |
| 3 | ✗ | 使い終わったメモリを回収する |
| 4 | ✓ | 自動回収だがSTWがある |
オリジナル問題2(世代別GC)
世代別GCに関する次の記述のうち、正しいものはどれか。
- 世代別GCは古いオブジェクトほどすぐ死ぬ前提で、古い置き場だけを頻繁に片付ける方式だ
- 世代別GCは新しいものはすぐ死ぬ前提で、新しい置き場を頻繁に・古い置き場をたまに片付ける
- 世代別GCは紙に印刷する手順のことで、メモリの管理とは無関係なものだとされているのだ
- 世代別GCはすべてのオブジェクトを必ず同じ頻度で片付け、世代を分けないものだとされている
解答は 2 ですよ。
世代別GCは新しいものはすぐ死ぬ前提で、新しい置き場(Young)を頻繁に・古い置き場(Old)をたまに片付けますね。効率がよく、Javaの主流です。
選択肢1の「古いものほどすぐ死ぬ」、選択肢3の「印刷する手順」、選択肢4の「同じ頻度」はどれも誤りですよ。
| 選択肢 | 判定 | 理由 |
|---|---|---|
| 1 | ✗ | 新しいものほどすぐ死ぬ前提 |
| 2 | ✓ | 新しい置き場を頻繁に片付ける |
| 3 | ✗ | 印刷する手順ではない |
| 4 | ✗ | 世代を分けて頻度を変える |
オリジナル問題3(GCなしの言語)
GCと言語に関する次の記述のうち、正しいものはどれか。
- RustはGCを使わず所有権でメモリ管理し、JavaやPythonはGCを使う言語だ
- すべての言語はGCを使ってメモリを管理し、手動で管理する言語はないものだとされている
- RustはGCを使う言語で、JavaやPythonはGCを使わない言語だとされている
- GCを使うかどうかは紙に印刷する速度で決まり、言語とは無関係なものだとされているのだ
解答は 1 ですよ。
RustはGCを使わず所有権でメモリを管理し、JavaやPythonはGCを使う言語ですね。Rustはコンパイルのときにメモリ管理を保証します。
選択肢2の「すべてGCを使う」、選択肢3のRustとJavaが逆、選択肢4の「印刷する速度」はどれも誤りですよ。
| 選択肢 | 判定 | 理由 |
|---|---|---|
| 1 | ✓ | Rustは所有権・Java/PythonはGC |
| 2 | ✗ | 手動管理の言語(C・C++)もある |
| 3 | ✗ | RustとJava・Pythonが逆 |
| 4 | ✗ | 印刷の速度では決まらない |
まとめ
押さえどころ
- 🔴 GCとSTW = 使い終わったメモリを自動回収するが、片付け中に止まる時間(STW)がある。常に高速ではない。
- 🔴 代表的な方法 = マーク&スイープ(印をつけて回収)/世代別GC(新しいものはすぐ死ぬ前提)/参照カウント(数を数える・循環参照に弱い)。
- 🟡 GCなしの言語 = Rustは所有権でGCを使わずに管理。C・C++は手動。
次に学ぶ
- 現代言語(Rust・Go・TypeScript) ── GCを使わず所有権でメモリを管理する、Rustなどの現代言語。
- ページング(TLB・階層化) ── GCが回収する土台、メモリの住所を管理するページングのしくみ。
執筆: SikakuQuest編集部