Javaはどのように動くのか~図解でわかるJVMの仕組み

第5回 チューニングのために理解しておきたいGCの4つのアルゴリズム

この記事を読むのに必要な時間:およそ 2 分

「一世代ヒープ」の問題を考える

これまでのように,すべてのオブジェクトをGC対象とすることを「一世代ヒープ」と言います。一世代ヒープでは,起動時に生成されたオブジェクトも,GC間際に生成されたオブジェクトも同じヒープに格納されています。

図13 一世代ヒープ

図13 一世代ヒープ

アプリケーションでは,多くのオブジェクトはわずかな時間だけ利用され,長時間利用されるオブジェクトはごく少数です。

図14 一般的なオブジェクトの割合

図14 一般的なオブジェクトの割合

一世代GCでは,ヒープサイズが大きくなるとヒープに格納されるオブジェクト数が増え,GCの時間が長くなり,アプリケーションの停止時間が長くなってしまいます。

図15 ヒープが広すぎる

図15 ヒープが広すぎる

「世代別ヒープ」でGCの時間を減らす

では,ヒープサイズを大きくしても停止時間をできるかぎり短くするには,どうしたらいいのでしょうか?

答えは,わずかな時間だけ利用されるオブジェクトと長時間利用されるオブジェクトを分けて管理・GCし,GC対象となるオブジェクトを限定すれば,GCの時間を減らすことです。

そのような考え方を取り入れたのが「世代別ヒープ」です。

世代別ヒープでは,オブジェクトがGCされた回数を年齢(age)と呼びます。また,若い領域をYoung領域,古い領域をOld領域と表現することもあります。

図16 世代別ヒープ

図16 世代別ヒープ

若い領域には,オブジェクトが生成されてから間もないオブジェクトが格納されます。古い領域には,オブジェクトが生成されてから,一定回数GCが行われたオブジェクトが格納されます。

図17 各領域とオブジェクトの関係

図17 各領域とオブジェクトの関係

アプリケーションがオブジェクトを生成すると,若い領域のヒープを割り当てます)⁠

図18 世代別ヒープへのオブジェクトの生成

図18 世代別ヒープへのオブジェクトの生成

若い領域がいっぱいになると,若い世代のGCが行われます。若い領域にある死んだオブジェクトはここで解放されますが,若い領域にある生きたオブジェクトがある一定回数のGCを経験すると,若い領域から古い領域へコピーされます。

図19 若い世代のGC

図19 若い世代のGC

若い領域のヒープがいっぱいになると,若い領域だけをGCすることで,対象となるヒープやオブジェクトが少なくなります。

こうすることで,一世代で管理する場合に比べてGC時間が短くなり,アプリケーションの停止時間も短くなるのです。

図20 若い世代だけを対象とするGC

図20 若い世代だけを対象とするGC

若い領域のGCで一時的に使用されるオブジェクトを解放することで,古い領域に移動するオブジェクトは少なくなり,古い領域のGCが行われる回数を削減することができます。

図21 古い世代はめったにGCされない

図21 古い世代はめったにGCされない

今回で,HotspotやJRockitなど,JVMの実装に問われないGCの基礎知識は終わりになります。次回は,Hotspot JVMではこれらの実装がどのようになっているかをご紹介します。

※)
ただし,JVMの実装によっては,大きすぎるサイズのオブジェクトが古い領域にいきなり割り当てられることもありますのでご注意ください。

著者プロフィール

伊藤智博(いとうちひろ)

日本オラクル(株)コンサルティングサービス統括所属。アプリケーションアーキテクトやM/Wコンサルとして,Javaに限らずさまざまな言語での開発/支援を経験。アプリ ケーションだけでなくミドルウェア,データベース,OS,ハードウェアにも興味アリ。現在,以下のコミュニティの活動に協力している。

Japan Oracle User Group(JPOUG)
Oracle LOVERS

ブログ:http://chiroito.blogspot.jp/
Twitter:@chiroito