Jump to content 日本-日本語

製品  >  ソフトウェア  >  HP- UX Developer Edge

Javaのかなめ、
「ガベージ・コレクション」をやさしく学ぶ・前編

HP-UX/Integrityサーバー お問い合せ
コンテンツに進む
Javaのかなめ、「ガベージ・コレクション」をやさしく学ぶ・前編
Javaの「ガベージ・コレクション」は、開発者にとって“諸刃の剣”とも言える機能だ。面倒なメモリ管理を自動化し、開発生産性を高めてくれる一方で、場合によってはJavaアプリケーションのパフォーマンス・ボトルネックともなる。ガベージ・コレクションのメカニズムを理解し、その得手不得手を把握しておけば、開発生産性とパフォーマンスを両立させる強力な武器となるだろう。ここでは、HotSpot VMに備わる「世代別ガベージ・コレクション」の仕組みをあらためて学び、またJ2SE 5.0以降でサポートされた新機能の概要を紹介する。
Javaのかなめ、「ガベージ・コレクション」をやさしく学ぶ・前編
HotSpot VMのガベージ・コレクションをおさらいする
マイナーGCで「ふるい」にかける
2007年2月
テクニカルライター 吉川和巳

HotSpot VMのガベージ・コレクションをおさらいする

まずは、現行のJava仮想マシン(以下、JVM)である「HotSpot VM」で採用されている、「世代別ガベージ・コレクション」のメカニズムをおさらいしておこう。

例えばLISPやSmalltalkといったガベージ・コレクション(以下、GC)を備える古典的なプログラミング言語や、Javaの初期のJVMでは、実行プロセスのメモリ領域にすべてのオブジェクトが分け隔てなく格納されていた。

単一のメモリ領域
図1:単一のメモリ領域

これらの環境では、使用済みの不要なオブジェクトがメモリ領域を圧迫し、新しいオブジェクトのための領域を確保できなくなると、「マーク&スイープ(mark & sweep)GC」と呼ばれるGCが実行される。具体的には、メモリ領域上のすべてのオブジェクトの参照関係をたどり、ひとつひとつのオブジェクトに「他のオブジェクトから参照されている(=使用中である)」ことを示すマークを付けていく。最後に、マークの付いていない使用済みオブジェクトをスイープ(掃除)するという方式のGCである。

このGC方式の欠点は、GC中はすべてのアプリケーションの実行を一時停止しなくてはならない点だ。例えばメモリ領域のサイズが数100MB〜数GBといった大きさになると、数秒〜数10秒もの時間をGCに費やすこともある。こうした長時間のアプリケーション停止は、とりわけサーバ環境では大きな問題となる。ちなみに、このように全アプリケーションの停止が必要なGCは、「stop-the-world(時間よとまれ)方式」とも呼ばれる。

マーク&スイープの欠点を補う世代別GC

こうしたマーク&スイープGCの欠点を補うべく生み出されたのが、世代別GCである。現在のHotSpot VMでは、JVMのメモリ領域(ヒープ)が「Young領域」、「Old領域」、および「Perm領域」の3つに分割されている。

JVMの3つのメモリ領域
図2:JVMの3つのメモリ領域

これらは、それぞれ以下のような目的で使用される。
  • Young領域:生成直後の“新しい”オブジェクトを保存する領域
  • Old領域:生成後しばらく経過した“古い”オブジェクトを保存する領域
  • Perm領域:ロード済みのクラスなど、半永久的なデータを保存する領域
このようにヒープをオブジェクトの世代別に分ける理由は、Javaアプリケーションには「オブジェクトの大半は生まれてすぐに不要になる」という一般的な性質があるからだ。例えば文字列を表すStringオブジェクトなどは、Javaアプリケーションの内部で何万という数が生成されるが、そのほとんどがすぐに使用済みとなってしまう。よって、そうした新しいオブジェクトを納めたYoung領域についてのみGCをこまめに実行することで、ヒープ全体を対象としたマーク&スイープGCの頻度を大幅に減らせるのである。ちなみに、Young領域を対象とした小規模なGCを「マイナーGC(またはScavenge GC)」といい、ヒープ全体の大規模なGCを「メジャーGC(またはフルGC)」と呼ぶ。

マイナーGCは対象となる領域サイズが小さく、1回あたり数ms程度の短い時間で完了するため、Javaアプリケーションへの影響は少ない。一方、メジャーGCは数100MB〜数GBのヒープ全体を対象とするため、完了までに数秒〜数10秒という長い時間を要する。よって、「Javaアプリケーションの実行中に生じる使用済みオブジェクトはすべてマイナーGCで除去し、メジャーGCは極力発生させない」というのが、Javaパフォーマンス・チューニングにおけるゴールのひとつとなる。

以下の図は、サンが無償で公開しているJavaプロファイリング・ツール「Visual GC」を用いて、そうした世代別GCの実際のふるまいを可視化したものである。

Visual GCで可視化された各領域の使用量変化
図3:Visual GCで可視化された各領域の使用量変化

ここで注目していただきたいのは、画面中央の「Eden Space(Eden領域)」と、画面下の「Old Gen(Old領域)」、「Perm Gen(Perm領域)」である。Eden領域については追って説明するが、Young領域の一部分と考えていただきたい。

上記例のEden領域において、メモリ使用量が定期的にがくんと減っている個所は、マイナーGCによってEden領域内のオブジェクトが一掃されたことを示す。一方、Old領域とPerm領域のメモリ使用量の増加はなだらかであり、メジャーGCは全く実行されていないことが分かる。

つづいて後半では、Young領域を対象に実行されるマイナーGCのメカニズムを掘り下げる。

トップへ   次のページへ

本ページの内容は執筆時の情報に基づいており、異なる場合があります。
印刷用画面へ
プライバシー ご利用条件・免責事項