Skip to content
Latchkey

Garbage Collection とは?自動的なメモリのクリーンアップ

garbage collection(GC)は自動的なメモリ管理です。runtime がどのオブジェクトがまだ到達可能かを追跡し、到達不能なもののメモリを解放します。

garbage collection を持つ言語では、オブジェクトを作成してメモリを確保しますが、明示的に解放することはほとんどありません。バックグラウンドの仕組みである garbage collector が、プログラムのどの経路からも到達できなくなったオブジェクトを定期的に見つけ、そのメモリを回収します。これにより、多少の runtime オーバーヘッドと時折の一時停止と引き換えに、手動メモリ管理のバグの一群がまるごとなくなります。

GC が何を解放するか決める方法

collector は「roots」(グローバル変数、stack、アクティブな参照)から始めて、そこから到達可能なすべてのオブジェクトをたどります。到達されなかったものはゴミであり、解放できます。この到達可能性モデルこそが、忘れられた参照が予想より長くメモリを生かし続ける理由です。

一般的な回収戦略

  • Mark-and-sweep: 到達可能なオブジェクトをマークし、残りを一掃します。
  • Generational: 寿命の短い若いオブジェクトは頻繁に、古いものはまれに回収します。
  • Reference counting: 参照カウントがゼロになったときにオブジェクトを解放します。
  • Compacting: 生きているオブジェクトを寄せ集めて断片化を減らします。

GC が支払わせるコスト

garbage collection は手動の制御を安全性と引き換えにします。その代償は heap をたどるために費やされる CPU と、一部の collector では GC が動作できるようプログラムが一瞬止まる一時停止です。現代の collector はこれらの一時停止を最小化しますが、完全になくなることはありません。

GC はすべての leak を防ぐわけではない

garbage collector は到達不能なメモリだけを解放します。コードが参照を生かし続けると(cache、リスト、event listener の中で)、そのオブジェクトはまだ到達可能で、決して回収されません。これは garbage collection のある言語であっても memory leak です。

簡単な例

JavaScript や Java のプログラムでは、どの変数もオブジェクトを指さなくなった時点で、collector は次のサイクルでそれを回収してよくなります。あなたからの free() 呼び出しは不要です。単にそのオブジェクトの参照をやめるだけです。

CI における GC

test run や build は heap を圧迫することがあり、メモリが埋まるにつれて GC のオーバーヘッドは増えます。プロセスが利用可能なメモリを超えると、runner はテストの途中でそれを OOM-kill することがあります。より大きな runner(Latchkey)は collector により多くの余裕を与え、一時的な OOM kill は自動 retry できるため、メモリのスパイクが本来問題のない build を失敗させずに済みます。

重要なポイント

  • garbage collection は、プログラムがもう到達できないオブジェクトのメモリを自動的に解放します。
  • 手動解放のバグをなくしますが、CPU のコストがかかり、時折の一時停止を引き起こすことがあります。
  • GC は leak を防ぎません。まだ到達可能な参照があると、メモリは永遠に生き続けます。

関連ガイド