コンピューターサイエンス:アルゴリズム / OS / ネットワーク / DB
ガベージコレクション概要
ガベージコレクション概要
このレッスンで分かること
- ガベージコレクション(GC)は 不要になったメモリをランタイムが自動で解放する仕組み です
- 主要なアルゴリズムは 参照カウント、マーク & スイープ、世代別 GC、コピー GC の 4 つです
- GC のおかげで
free忘れによるメモリリークから解放される一方、停止時間(GC pause)という代償も生じます
ガベージコレクション概要 とは
ガベージコレクション概要。本レッスンでは、ガベージコレクション概要 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
GC アルゴリズム比較 (要点)
| アルゴリズム | 採用例 | 強み | 弱み |
|---|---|---|---|
| 参照カウント | Python (主)、Swift ARC | 即時回収、停止短い | 循環参照に対応不可 |
| マーク & スイープ | 古典 Java、Lisp 系 | 循環 OK | 全停止が長くなりがち |
| コピー GC | 若い世代でよく使用 | フラグメンテーションなし | メモリ 2 倍必要 |
| 世代別 GC | Java HotSpot G1、Mono SGen、Python (循環用) | 平均高速 | 実装が複雑 |
| 並行 GC | Java ZGC / Shenandoah、Go | 停止時間 ms 以下 | スループットやや劣る |
手動管理 vs 自動管理
C や C++ は手動でメモリを管理します。malloc / new で確保し、free / delete で解放しなければ メモリリーク、解放済みのメモリにアクセスすると use-after-free で未定義動作になります。
Java、Python、JavaScript、Go、Ruby、C#、Swift などは GC(または参照カウント + ARC)でメモリを 自動回収 します。プログラマは「いつ解放するか」を考えずに済む代わりに、ランタイムが定期的にメモリを掃除します。
アルゴリズムの比較
| 方式 | 仕組み | 長所 | 短所 |
|---|---|---|---|
| 参照カウント | オブジェクト参照数を数え、0 で解放 | 即時回収、停止短い | 循環参照を解放できない |
| マーク & スイープ | 到達可能を辿り、それ以外を解放 | 循環 OK | 全停止が長くなりがち |
| コピー GC | 生きているものを別領域にコピー、元を捨てる | フラグメンテーション無し | メモリ 2 倍必要 |
| 世代別 GC | 若い世代を頻繁、老世代を時々 | 平均的に高速 | 実装が複雑 |
マーク & スイープの図解
ルート(スタック上のローカル変数、グローバル変数など)から辿れる A B C D は生きており、E と F はどこからも辿れないので回収対象になります。E と F が互いに参照していても、ルートに繋がっていないので回収できる点が参照カウントとの違いです。
世代別 GC
経験則として「ほとんどのオブジェクトは生まれてすぐ死ぬ」が知られています(弱い世代仮説)。そこで若い領域(Young / Eden)と老成領域(Old / Tenured)に分け、若い領域を 頻繁・短時間 に掃除し、長く生き残ったオブジェクトだけ老成領域に昇格させます。
| 世代 | サイズ | GC 頻度 | コスト |
|---|---|---|---|
| Eden | 小 | 高 | 低 |
| Survivor | 中 | 中 | 中 |
| Old | 大 | 低 | 高(Full GC) |
Java HotSpot の G1、Python の世代別 GC、Mono の SGen など、現代の主要ランタイムが採用しています。
具体例 (Python)
Python
import gc
gc.set_debug(gc.DEBUG_STATS)
a = [1, 2, 3]
b = [a, a, a]
del a, b
gc.collect() # 強制実行Python は 参照カウント がメインで、循環参照だけ追加の 世代別 GC がカバーしています。sys.getrefcount(obj) で参照数を覗けます。
トレードオフ
- GC のメリットは 生産性と安全性。リークやダングリングポインタが大幅に減ります
- デメリットは 停止時間。Stop-the-World GC が起きると数十 ms ~ 数秒間、アプリ全体が固まります。低遅延 GC(ZGC、Shenandoah、Go の concurrent GC)はこのギャップを ms 以下に縮めます
- 「Rust や C++ で手動管理」と「Go や Java で GC」を比べると、メモリ使用量とレイテンシが要件次第で逆転します
OS との関係
GC は通常、プロセス内のヒープ を管理し、OS にはメモリを返さない場合もあります。RSS(Resident Set Size)が減らないように見えるのはこのためです。返したい場合は madvise(MADV_DONTNEED) などのシステムコールを呼びます。
よくある誤解
- 「GC があればメモリリークは起きない」は誤りで、参照を残したまま手放さなければ(キャッシュ、リスナー登録、グローバル辞書)リークは普通に起きます
- 「参照カウントは GC ではない」は半分正解で、文献によっては別物扱い、別の文献では GC の一種とされます。実態としては両者を組合せる例(CPython)が多いです
やってみよう
Python REPL で import sys; x = []; sys.getrefcount(x) を実行し、変数代入時に参照が 1 つ増えるのを観察してください。次に y = x で増え、del y で減るのが見えます。
まとめ
このレッスンの要点は、GC の 4 大アルゴリズム / 世代別の弱い世代仮説 / 停止時間 vs スループット の 3 点です。実務でこれらを切り分けて説明できるようになると、設計レビューや障害対応の精度が一段上がります。
理解度チェック
Q. 参照カウント方式の 最大の弱点 は?
- 実装が複雑すぎる
- 循環参照しているオブジェクト群を解放できない
- メモリが 2 倍必要になる
- 停止時間が必ず数秒に及ぶ
答えを見る
正解は 2。参照カウントは参照数 = 0 で解放しますが、A→B→A のような循環参照は互いに参照を持ち続けるので 0 にならず解放されません。Python は補助に世代別 GC を併用して解決しています。
出典 (References)
最終更新: 2026-05-28
関連レッスン
よくある質問
Q. このトピックは実務でどう役立ちますか?
A. DB のクエリ最適化、API 設計、データ構造の選択など、設計判断の根拠になります。表面的にライブラリを使うだけでなく「なぜそれが速いのか」を理解できると、性能問題を未然に防げます。コーディング面接でも頻出のテーマです。
Q. 計算量はどう求めれば良いですか?
A. ループのネストごとに掛け算する、再帰なら漸化式から解く、というのが基本です。Big-O 表記は定数倍と低次の項を無視するため、n の指数(n²、n log n など)に注目してください。最悪・平均・最良の 3 つを意識すると説得力が増します。
Q. 覚えるべき定番アルゴリズムは何ですか?
A. 二分探索、クイックソート/マージソート、BFS/DFS、ダイクストラ、DP の基本問題(フィボナッチ・ナップサック)が必修です。これらを「白紙から書ける」状態にすると、応用問題が一気に解けるようになります。
次のレッスン
次は ファイルシステムとは で、ガベージコレクション概要 を学びます。
事前確認 — 進む前に次の 3 つができることを確認しましょう。
- GC概要 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (30 秒)
Q. GC概要 とは何か、1 文で説明してください。
A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。
関連レッスン