Javaがヒープの管理にGCを使用しているのは、読者の皆さんもご存じの通りです。GCの手法にはいろいろありますが、HotSpot VMが採用しているのが世代別GCです。今回は、世代別GCの概要と問題点を解説したうえで、これを解決するために導入されたGarbage First GCについて説明します。

世代別GCの概要と問題点

 世代別GCは若いインスタンスと時間を経たインスタンスを別々の領域に配置し、管理する手法です。これは寿命の短いインスタンスほど多いという性質をベースにしています。

 若いインスタンスが配置される領域をヤング領域、時間を経たインスタンスを配置する領域をオールド領域とよび、それぞれの領域で異なるGCの手法を使用します。つまり、ヤングとオールドという世代の異なる領域を、それぞれ異なるGCで管理するのが世代別GCというわけです。

 ヤング領域には高速ですが漏れのあるGCを用います。逆にオールド領域には低速ですが漏れのないGCを使用します。

 HotSpot VMではヤング世代にはコピーGC、オールド世代にはコンカレント マーク&スイープGC (CMS)を使用しています。

 コピーGCはその名の通り、インスタンスを領域間でコピーする手法です。HotSpot VMではヤング領域をEden領域と2つのSurvivor領域に分割します。

 インスタンスを生成する時には、必ずEden領域にアロケーションします。Eden領域がいっぱいになると、Eden領域の生き残っているインスタンスをSurvivor領域にコピーします。この時、Survivor領域は交互に使用し、Eden領域からSurvivor領域にへのコピー時に、もう一方のSurvivor領域にある生き残っているインスタンスもコピーします。

 複数回コピーGCを生き残ったインスタンスは寿命が長いと見なされ、オールド領域のTenured領域にコピーされます。

 コピーGCはその名の通り、インスタンスを頻繁にコピーします。したがって、コピーするインスタンスが多量になったり、ヤング領域のサイズが大きくなると効率が低下してしまいます。

 オールド領域のGCであるCMSは古典的なGCの手法であるマーク&スイープを並列化したGCです(実際にはヤング領域も含めたすべての領域がGCの対象となります)。

 マーク&スイープはルートとなるインスタンスから参照をたぐってインスタンスをマークするフェーズと、マークされなかった(すなわち使われていない)インスタンスを回収するスイープフェーズから成り立ちます。

 どちらのフェーズもすべてのスレッドを一時中断して行います。しかし、これではプログラムがストップしてしまう時間が非常に長くなってしまいます。