Cosminexus システム設計ガイド
ここでは,ガーベージコレクションの仕組みについて説明します。
ガーベージコレクションは,プログラムが使用し終わったメモリ領域を自動的に回収して,ほかのプログラムが利用できるようにするための技術です。
ガーベージコレクションの実行には,処理時間が掛かります。このため,ガーベージコレクションを適切に実行できるかどうかが,システムの処理性能に大きく影響します。
プログラムの中でnewによって作成されたJavaオブジェクトは,JavaVMが管理するメモリ領域に格納されます。Javaオブジェクトが作成されてから不要になるまでの期間を,Javaオブジェクトの寿命といいます。
Javaオブジェクトには,寿命の短いオブジェクトと寿命の長いオブジェクトがあります。サーバサイドで動作するJavaアプリケーションの場合,リクエストやレスポンス,トランザクション管理などで,多くのJavaオブジェクトが作成されます。これらのJavaオブジェクトは,その処理が終わると不要になる,寿命が短いオブジェクトです。一方,アプリケーションの動作中使用され続けるJavaオブジェクトは,寿命が長いオブジェクトです。
効果的なガーベージコレクションを実行するためには,寿命の短いオブジェクトに対してガーベージコレクションを実行して,効率良くメモリ領域を回収することが必要です。また,繰り返し使用される寿命の長いオブジェクトに対する不要なガーベージコレクションを抑止することが,システムの処理性能の低下防止につながります。これを実現するのが,世代別ガーベージコレクションです。
世代別ガーベージコレクションでは,Javaオブジェクトを,寿命が短いオブジェクトが格納されるDefNew領域と,寿命が長いオブジェクトが格納されるTenured領域に分けて管理します。DefNew領域はさらに,newによって作成されたばかりのオブジェクトが格納されるEden領域と,1回以上のガーベージコレクションの対象になり,回収されなかったオブジェクトが格納されるSurvivor領域に分けられます。DefNew領域内で一定回数以上のガーベージコレクションの対象になったJavaオブジェクトは,長期間必要なJavaオブジェクトと判断され,Tenured領域に移動します。
世代別ガーベージコレクションで管理するメモリ空間とJavaオブジェクトの概要を次の図に示します。
図8-1 世代別ガーベージコレクションで管理するメモリ空間とJavaオブジェクトの概要
1回目のガーベージコレクションが実行された時点で使用されていたJavaオブジェクトは,DefNew::Eden領域からDefNew::Survivor領域に移動します。なお,このときにすでに使用されていなかったJavaオブジェクトは,移動しないで破棄されます。Tenured領域に移動するしきい値をn回とした場合,n回以上のガーベージコレクションが実行される間使用され続けていたJavaオブジェクトは,DefNew::Survivor領域からTenured領域に移動します。なお,1回以上のガーベージコレクション実行時に使用されていて,n回未満のガーベージコレクション実行時に使用されなくなっていたJavaオブジェクトは,その時点で移動しないで破棄されます。
なお,世代別ガーベージコレクションで実行されるガーベージコレクションには,次の2種類があります。
一般的に,コピーガーベージコレクションの方が,フルガーベージコレクションよりも短い時間で処理できます。このため,JavaVMのチューニングでは,JavaVMオプションでそれぞれのメモリ空間のサイズや割合を適切に設定することで,フルガーベージコレクションが頻発することを防ぎ,パフォーマンス低下を防ぐようにします。
オブジェクトがコピーガーベージコレクションの対象になった回数をオブジェクトの年齢といいます。
オブジェクトの寿命と年齢の関係を次の図に示します。
図8-2 オブジェクトの寿命と年齢の関係
アプリケーションが開始して初期化処理が完了したあとで,何度かのコピーガーベージコレクションが実行されると,長期間必要になる寿命の長いオブジェクトはTenured領域に移動します。このため,アプリケーションの開始後しばらくすると,Javaヒープの状態は安定し,作成されるJavaオブジェクトとしては,寿命が短いオブジェクトが多くなります。特に,DefNew領域のチューニングが適切にできている場合,Javaヒープが安定したあとの大半のオブジェクトは,1回目のコピーガーベージコレクションで回収される,寿命が短いオブジェクトになります。
JavaVMでは,コピーガーベージコレクションの対象になるDefNew領域のメモリ空間を,DefNew::Eden領域,DefNew::Survivor領域に分けて管理します。さらに,DefNew::Survivor領域は,From空間とTo空間に分けられます。From空間とTo空間は,同じメモリサイズです。
DefNew領域の構成を次の図に示します。
図8-3 DefNew領域の構成
DefNew::Eden領域は,newによって作成されたオブジェクトが最初に格納される領域です。プログラムでnewが実行されると,DefNew::Eden領域のメモリが確保されます。
DefNew::Eden領域がいっぱいになると,コピーガーベージコレクションが実行されます。コピーガーベージコレクションでは,次の処理が実行されます。
この結果,DefNew::Eden領域とTo空間は空になり,使用中のオブジェクトはFrom空間に存在することになります。
コピーガーベージコレクション実行時に発生するオブジェクトの移動を次の図に示します。
図8-4 コピーガーベージコレクション実行時に発生するオブジェクトの移動
このようにして,使用中のオブジェクトは,コピーガーベージコレクションが発生するたびに,From空間とTo空間を行ったり来たりします。ただし,寿命の長いオブジェクトを行き来させ続けると,コピー処理の負荷などが問題になります。これを防ぐために,From空間とTo空間でJavaオブジェクトを入れ替える回数にしきい値を設定して,年齢がしきい値に達したJavaオブジェクトはTenured領域に移動させるようにします。
年齢がしきい値に達していないJavaオブジェクトがTenured領域に移動することを,退避といいます。退避は,コピーガーベージコレクション実行時にDefNew::Eden領域およびFrom空間で使用中のオブジェクトが多くなり,移動先であるTo空間のメモリサイズが不足する場合に発生します。この場合,To空間に移動できなかったオブジェクトが,Tenured領域に移動します。
図8-5 オブジェクトの退避
オブジェクトの退避が発生した場合,Tenured領域に本来格納されないはずの寿命の短いオブジェクトが格納されます。これが繰り返されると,コピーガーベージコレクションで回収されるはずのオブジェクトがメモリ空間に残っていくため,Javaヒープのメモリ使用量が増加していき,最終的にはフルガーベージコレクションが発生します。
オブジェクトの退避が発生した場合のメモリ使用量の変化について,次の図に示します。
図8-6 オブジェクトの退避が発生した場合のメモリ使用量の変化
このような要因で発生するフルガーベージコレクションは,システムの処理性能を低下させます。
したがって,メモリ空間の構成とメモリサイズを検討するときには,オブジェクトの退避が発生しないように,DefNew::Eden領域とDefNew::Survivor領域のバランスを検討する必要があります。
All Rights Reserved. Copyright (C) 2006, 2008, Hitachi, Ltd.