ガベージコレクション(GarbageCollection)とは、動的に確保されたメモリ領域のうち、使われなくなった領域(garbage:ゴミ)を自動的に収集(collection)して解放する機能。ガベージコレクションを行うモジュール(実装)の事をガベージコレクタ(GarbageCollecter,GC)と言う。
ガベージコレクションは言語や標準ライブラリ、OSといった環境に組み込まれて提供される。
ガベージコレクションの必要性
プログラムが動作するとき、プログラムが使うデータを格納するためにメモリ領域を確保するが、プログラミングの時点でサイズが決まっていないデータ、実行中にサイズが変化するデータについては、メモリを動的に確保する。この、動的に確保されたメモリ領域は、動的に解放を行わなければならない。
解放を行わないと、もう使わないのに確保されたままのメモリ領域(=メモリリーク)が発生し、システムが利用できるメモリは減っていく。最終的にシステムが重くなったり、不安定になり、ひどければアプリケーションの起動ができなくなることもある。
初期のプログラミング言語ではメモリを効率的に使うために、すべてのメモリの確保と解放をプログラマが人力で管理していた。しかし、これはそれなりの技術力を要求するため、プログラマのハードルを上げてしまっていた。
現在でもC/C++といった言語には、標準の言語仕様(ライブラリを除いた言語自体の仕様)ではこの機能は存在しない。特にC言語の場合、標準添付ライブラリでは仕様上では存在しない。
なお、このことで必然的に発生しうるメモリフラグメンテーションを解消すべく、メモリの連続未使用領域の確保を行うことをガベージコレクションと呼ぶことがある。厳密にはこれはメモリコンパクションと呼び、正確とは言いがたい。ガベージコレクションの実装としてメモリコンパクションの機能が内包されているケースが多く、同一の意味合いで用いられることがあるので注意と理解が必要である。
利点と欠点
メモリの確保を人力で管理するのは大変で面倒。なので、コンピュータにさせよう!という話になる。プログラマは面倒ごとをコンピュータに任せたがる人種なのだ。
利点
この動的に解放を行うという事を、プログラマが意識しなくてよいように、言語や標準ライブラリに組み込まれたのがガベージコレクションと呼ばれる機能である。これによってプログラマは、メモリの解放を意識せずにたくさんのメモリをより自由に使えるようになった。また、プログラミングの敷居を下げた。
また、個々のプログラマが独自にメモリ管理を行う代わりに、ガベージコレクションを環境とセットにして実装し他のプログラマに提供することで、より洗練された高速なガベージコレクション機能の恩恵を多くのプログラマが受けることにもなる。すげぇ人が作ったすげぇガベージコレクタを、みんなで使った方が効率いいよね?ということ。
無論、標準ではGCが存在しないC言語もライブラリを使えば利用可能である。
欠点
ただし、欠点もある。ガベージコレクタが動くとき、ガベージコレクタ自身がCPUを消費してしまう。アルゴリズムにも寄るが、ガベージコレクタはプログラムが使用しているメモリ全体をチェックするため、非常に負荷がかかる。また、ガベージコレクション処理が完了する時間も一般的なGCでは予測できない。(予測可能なアルゴリズムもあるにはある)
メモリ管理をプログラマが意識せずに済むことの対価として、プログラマはガベージコレクタを細かく制御できない。そのため、予測しないタイミングでCPUに高負荷がかかり、本来のプログラムの実行に処理が回らないといったことが起きる可能性がある。このため、リアルタイム性が要求されるプログラムには不向きと言われる。
よくある誤解
ガベージコレクションは手動管理に比べて処理が重いと思われていることが多いが、これは必ずしも正しくない。ガベージコレクション特有のコストがあるのは確かだが、そもそも手動管理を行う場合でもメモリの確保・解法に掛かる実行コスト自体は同じなのだ。例えば、プログラムがアイドル状態の時にGCを行うといった最適化が行われれば全体的な性能は向上する可能性がある。また、別スレッドにおいてメモリの管理を行うことで性能低下を殆ど起こさないようにGCを行える場合もあるだろう。(これらが可能かどうかはプログラムの動作や、メモリがどのように使用されているか、そしてGCの性能に依る)
では何故ガベージコレクションに重い印象が付きまとうかというと、欠点の項にあるように一度動き出すとその時にまとめて負荷が掛かる傾向があるためである。つまりこれはゴミはこまめに捨てたほうが良いのか、普段は貯めておいてたまに大掃除をした方が良いのかということであり、プログラムの性能が途中で変動して問題ないのかどうかにかかってくる。
というわけで「負荷軽減のために手動管理する」というのは正しい理解ではないことを覚えておきたい。時に手動管理する方が有利なのは、あくまでその方が動きを予測できるからなのだ。
注意事項
各メモリ領域を参照するポインタの数を監視し、これがゼロになった領域を不要な領域として解放していく手法を中心とすることが多いが、プログラムコードが、不要な保存域を参照し続けるようなつくりになっていると、せっかくのガベージコレクションも役に立てない。
例えば、C#によるGUIプログラミングにおいて、Formのメンバ変数が膨大なDictionaryを持ち続けているであるとか、Javaによるサーバサイドプログラミングにおいて、HttpSessionへsetAttributeなどでどんどん値を追加していくとか、そのような実装を行っている場合、たとえその内容が使用されないものであったとしても、ガベージコレクタはこれらの領域が不要であると判断することができず、従来のメモリリークと同様の現象が発生する。
歴史
BASICやFortranなどの、古い高級言語には独自のメモリ管理機構があった。これをガベージコレクションと呼ぶかどうかは分からない。
ガベージコレクタが初めて実装されたのは、Lisp言語だといわれている。ただし、当時のコンピュータ性能ではガベージコレクション機能は荷が重く、実用にはならなかった。研究機関や教育機関では利用されていたが、一般への普及にはコンピュータ性能が上昇するのを待たなければならなかった。
90年代後半になるまで、開発言語はC/C++が一般的であり、ガベージコレクションはそもそもない(C)か、あるにはあるがまともに使えなかった(C++のauto_ptr。現在はshared_ptrとweak_ptrなどでそれなりにまともに扱える)。
Java言語が光を浴びると、JavaVMに搭載されたガベージコレクションが有名になった。当時主流だったC/C++のスタイルを受け継ぎ、言語的にもすっきりさせたJavaは、多くの言語に影響を与えた。Javaの影響を受けC#が作られた。
一方でPerlなどスクリプト言語は当初からガベージコレクタを持っている。これは、スクリプト言語自体がメモリ管理といった面倒ごとからプログラマを解放することを目的として作られているからだ。同類のJavaScript、PHP、Ruby、Pythonなども同様の思想と共に、ガベージコレクタを受け継いでいる。
現在では、C#やJava、Objective-Cといった、性能が潤沢なコンピュータ向けの言語はガベージコレクタを持つようになる傾向にある。一方で、携帯電話やゲーム機といった、性能が低いコンピュータや、処理性能を必要とされる環境では、依然ガベージコレクタを使わない状態が続くと思われる。
付加機能
動的メモリ領域の断片化(フラグメンテーション)に対する再配置機能も含めて、ガベージレコクションと呼ばれることもある。
関連動画
関連書籍
関連項目・外部サイト
- ガベージコレクタ
- C#
- Java
- D言語
- プログラミング関連用語の一覧
- GCアルゴリズム詳細解説 - 日本語でGCについてまとめてあるサイト
- 7
- 0pt