Java VMのGC
Java VMには様々な種類のGC(ガーベジコレクション)があり、用語を整理しないと混乱します。
GCの種類を整理する前に、まずJava VMのGCは「世代別GC方式」を採っていることを意識しましょう。
Java 7で正式サポートが始まったG1 GCも、世代別GC方式がベースになっています。
「世代別GC方式」の詳細は、様々なWebサイトで紹介されているので、ここではポイントだけを記述します。
世代別GC方式とは
Java VMはJavaヒープを、
「New領域(1個)」「Tenured領域(1個)」と「Permanent領域(1個)」に分割し、
さらに「New領域」を「Eden領域(1個)」と「Survivor領域(2個)」に分割します。
生成されたオブジェクトはまずEden領域に入り、最初の数回の「コピーGC」によって2個のSurvivor領域の間を行き来します。それでも生存し続けたら、最後にTenured領域に昇華されます。
Permanent領域には、主にクラス情報が入ります。
このようにメモリ領域をいくつかの領域に分け、各領域に応じて異なる種類のGCを実行する方式が、「世代別GC方式」です。
2個あるSurvivor領域は常に片方が空き領域になっていて、この意味でメモリ容量を余分に消費しますが、コピーGCは効率的なGCです。
Tenured領域はGCを繰り返すと断片化がひどくなり、大きなオブジェクトを割り当てられなくなる場合があります。このようなときは、オブジェクトを一か所に集めて断片化を解消するための「コンパクション」を行います。
Tenured領域を対象としたGCには、FullGCとCMS GCの2種類があり、前者はコンパクションを兼ねますが、Stop the world(アプリケーションが完全に止まる)が起きます。後者はStop the worldを起こしませんが、コンパクションを行いません。また、FullGCでは、Tenured領域に限らずPermanent領域もCGの対象となります。
Java VMオプションでCMS GCを選択した場合、CMS GCを実行してもTenured領域とPermanent領域にオブジェクトを割り当てられない場合、フォールバックとして、コンパクションを行うために自動的にFullGCが実行されます。
用語の整理
世代別GC:
Java VMが採用している全体的なGC方式。
コピーGC:
New領域を対象とした効率的なGC。
Java VMオプションで単一スレッドで実行するか、複数スレッドで実行するかを選択可能。
FullGC:
Tenured領域とPermanent領域を対象としたGCであり、アプリケーションの動作を完全に止めてしまう。
コンパクションも行う。
CMS GC:
Tenured領域を対象としたGC。Stop the worldを回避するために、アプリケーションスレッドと同時に実行。
CMS GCを実行してもTenured領域とPermanent領域にオブジェクトを割り当てられない場合、フォールバックとしてFullGCを実行してコンパクションを行う。
G1 GC:
Java VMで正式サポートが開始された、64ビットの広大なメモリ空間を対象としたGC。
Javaヒープを細かく分割して、同じサイズの小さな領域をたくさん作り、Eden領域、Survivor領域またはTenured世代のどれかにする。
Java 7でのGCの選択
拙者ブログのJava™ 7でのガーベジコレクションの選択を参照してください。