7.15.1 G1GCの概要
GCは,プログラムが使用し終わったメモリ領域を自動的に回収して,ほかのプログラムが利用できるようにするための技術です。
GCの実行中は,プログラムの処理が停止します。このため,GCを適切に実行できるかどうかが,システムの処理性能に大きく影響します。
プログラムの中でnewによって作成されたJavaオブジェクトは,JavaVMが管理するメモリ領域に格納されます。Javaオブジェクトが作成されてから不要になるまでの期間を,Javaオブジェクトの寿命といいます。
Javaオブジェクトには,寿命の短いオブジェクトと寿命の長いオブジェクトがあります。サーバサイドで動作するJavaアプリケーションの場合,リクエストやレスポンス,トランザクション管理などで,多くのJavaオブジェクトが作成されます。これらのJavaオブジェクトは,その処理が終わると不要になる,寿命が短いオブジェクトです。一方,アプリケーションの動作中使用され続けるJavaオブジェクトは,寿命が長いオブジェクトです。
効果的なGCを実行するためには,寿命の短いオブジェクトに対してGCを実行して,効率良くメモリ領域を回収することが必要です。また,繰り返し使用される寿命の長いオブジェクトに対する不要なGCを抑止することが,システムの処理性能の低下防止につながります。これを実現するのが,世代別GCです。
世代別GCでは,Javaオブジェクトを,寿命が短いオブジェクトが格納されるNew領域と,寿命が長いオブジェクトが格納されるTenured領域に分けて管理します。New領域はさらに,newによって作成されたばかりのオブジェクトが格納されるEden領域と,1回以上のGCの対象になり,回収されなかったオブジェクトが格納されるSurvivor領域に分けられます。New領域内で一定回数以上のGCの対象になったJavaオブジェクトは,長期間必要なJavaオブジェクトと判断され,Tenured領域に移動します。
世代別GCで管理するメモリ空間とJavaオブジェクトの概要を次の図に示します。
G1GCの世代別GCで実行されるGCには,次の3種類があります。
-
Eden領域とSurvivor領域を対象にしたGCです。Javaオブジェクトの作成によって,Eden領域を使い切ると発生します。
- 注意
-
アプリケーションサーバでは,SerialGCとG1GC(UseG1GC)が選択できます。ほかのParallelGC,ConcurrentGC,IncrementalGCは使用できません。
-
Eden領域とSurvivor領域とTenured領域の一部を対象にしたGCです。Concurrent Markingと呼ばれるオブジェクトの解析処理に基づき発生します。Javaオブジェクトの作成によって,Eden領域を使い切ると発生します。
-
Tenured領域も含む,JavaVM固有領域全体を対象にしたGCです。Tenured領域やMetaspace領域,Humongous領域を新たに確保できないと発生します。
一般的に,YoungGCとMixedGCの方が,FullGCよりも短い時間で処理できます。
次に,GCの処理について,あるJavaオブジェクト(オブジェクトA)を例にして説明します。
- Eden領域で実行される処理
-
オブジェクトAの作成後,1回目のYoungGCまたはMixedGCが実行された時点で使用されていない場合,オブジェクトAは破棄されます。
1回目のYoungGCまたはMixedGCが実行された時点で使用されていた場合,オブジェクトAはEden領域からSurvivor領域に移動します。
- Survivor領域で実行される処理
-
Survivor領域に移動したオブジェクトAは,その後何回かYoungGCまたはMixedGCが実行されると,Survivor領域からTenured領域に移動します。移動する回数のしきい値は,JavaVMオプションやJavaヒープの利用状況によって異なります。図7-16では,しきい値をn回としています。
Survivor領域への移動後,n回目未満のYoungGCまたはMixedGCが実行された時点でオブジェクトAが使用されていなかった場合,オブジェクトAはそのYoungGCまたはMixedGCで破棄されます。
- Tenured領域で実行される処理
-
オブジェクトAがTenured領域に移動した場合,その後のYoungGCでオブジェクトAが破棄されることはありません。YoungGCは,Eden領域とSurvivor領域だけを対象としているためです。MixedGCが発生した場合は,Tenured領域内の一部のオブジェクトが破棄されます。
MixedGCで破棄されるオブジェクトの数よりも,Tenured領域に移動するオブジェクトの数が多い場合,Tenured領域の使用サイズは増加します。新たにTenured領域を確保できなくなると,FullGCが発生します。
JavaVMのチューニングでは,JavaVMオプションでそれぞれのメモリ空間のサイズや割合を適切に設定することで,不要なオブジェクトがTenured領域に移動することを抑止します。これによって,FullGCが頻発することを防ぎます。