1|2GCを適切に行わせるためのヒープサイズの設定JVMにGCを適切に行わせるにはヒープサイズを適切に設定(New領域サイズ、Old領域サイズ、領域サイズのバランスなど)する必要があります。適切なヒープサイズはアプリケーションに依存します。一般にヒープサイズが小さいとGCが頻発してアプリケーションのパフォーマンスが低下します。ヒープサイズが必要量を下回る場合はOutOfMemoryErrorが発生してアプリケーションが停止してしまいます。ヒープサイズが大きいと、GCの起動回数は減りますが、GC1回当たりの処理時間、すなわちアプリケーション停止状態が長くなり、アプリケーションの応答時間に問題が出る場合もあります。システムの物理メモリのフリー領域が不足するまでヒープサイズを大きくすると、物理メモリからスワップ領域へのページングが起こってしまい、かなりのパフォーマンスが劣化する可能性もあります。通常、ヒープサイズは実メモリより大きく取ることはありません。New世代領域(Eden領域、From領域[=To領域])、Old世代領域の各サイズはJVMのオプションで指定できます。ヒープサイズオプションサイズ-Xms初期ヒープサイズ(全体)-Xmx最大ヒープサイズ(全体)-Xmn(-XX:NewSize)New世代領域サイズ-XX:MaxNewSizeNew世代領域サイズ-XX:NewRatioNew世代領域とOld世代領域の比率(Old世代領域/New世代領域)-XX:SurvivorRatioNew世代領域とSurvivor領域の比率(Eden領域/From領域)-XX:TargetSurvivorRatioNew世代領域GC後のFrom領域内オブジェクトの割合目標-Xms、-Xmx(-Xms≦-Xmx)に異なる値を設定すると、ヒープサイズは起動時には-Xmsで指定された大きさですが、状況によってJVMがヒープが足りないと判断した場合は最大-Xmxで指定した大きさまで拡大します。これらの値を同じにするとヒープサイズ調整のオーバーヘッドがなくなりパフォーマンスが上がる場合もあります。GCの監視GCアルゴリズムから分かるように、短命オブジェクトに対してはNew世代領域で対処し、長命オブジェクトのみをOld世代領域に割り当てることによりGCの回数やGCにかかる時間が最も効率的になります。そのようにヒープサイズを調節することがパフォーマンスの向上につながります。基本的にはアプリケーションの短命オブジェクト、長命オブジェクトのサイズを見積もり、それに応じたヒープサイズを設定すればよいのですが、見積もりが容易でない場合があります。その場合は実際にアプリケーションを実行して、パフォーマンスを計測すると同時にGC回数、GC時間やヒープ内オブジェクト量などの状況を見ながらサイズを決めていくことができます。実行時のヒープ内のオブジェクト情報を得るにはいくつか手段があります。ヒープ全体サイズやフリーな領域のサイズを知るためにはアプリケーション内でjava.lang.RuntimeクラスのtotalMemory()メソッド(ヒープ全体のサイズ)や、freeMemory()(ヒープ内のフリーな領域のサイズ)を利用できます。Serverなどではアプリケーションサーバ管理コンソール画面でヒープ内のオブジェクトの変化をグラフで見ることもできます)。Interfaceを使ったhprofエージェント)オプションを使ってJVMを実行すると、JVMにシグナルを送ることによってその時点のヒープ内オブジェクトのスナップショットを得ることもできます(JVMPIはJVMに実験的に実装されています。1.5ではJVMを監視するための新しい標準APIの実装が計画されています)。詳細な分析をもってチューニングを行うためには、以下に述べるようにJVMにGC情報をログファイルにいったん出力させて、アプリケーション実行終了後にログファイルを基に分析を行うのがよいでしょう。GCに特化した情報を得るにはJVMにはGC情報をログとして出力させるオプションが各種あります。知りたいGC情報の内容に従ってオプションを設定します。以下の例は結果をログファイルに出力しています。出力の1行にGC1回に関する情報が対応します。上の例では、GC2回分の情報を表示しています。減っていることが分かります。)内の18112Kはそのときの全体のヒープサイズを表しています。最後項目の0.0035231secsはこのGCにかかった時間(この間アプリケーショ-ンは停止)を表しています。GCで表示)ことが分かります。世代領域それぞれについてのオブジェクト量の変化情報も得られます。HP-UXのJVMでは-Xverbosegcを指定することにより、さらに詳細なGCの種類、GCが起きた理由なども出力されます。以下にGCの監視に役立つ主なオプションを示しておきます(オプションのサポートに関しては出力フォーマットも含めて変更になる可能性があるので注意してください)。出力はすべてテキストファイルなので直接読めるのですが、出力された数字の羅列を直接見てもGCの様子を把握するのは難しいことです。ツールを利用することにより、出力データのサマリやメトリクスのグラフ化を行うことができ、GC分析をより効率よく行えます。フリーのツールとしてHPjtuneやGCViewerなどがあるので、これらを利用するのがよいでしょう。アプリケーションのパフォーマンス(スループットやレスポンスタイム)を計測すると同時に、これらのオプションやツールを使いGCの回数、GCにかかった時間、GCの種類など分析して、ヒープのサイズが適切であるかどうかを判断し調節することができます。1.4.1からは大規模なシステム(大メモリ、多CPU)に対してスループット向上とGCによる停止時間減少を目的とした新たなGCも実装しています。現時点ではまだ実行環境状況によっては安定した動作をしない場合もあるようなので注意が必要です。-XX:+UseParallelGC、-XX:+UseParNewGC)標準のGCではNew世代領域に対してシングルスレッドでGCを行っていましたが、パラレルGCでは複数スレッドを使って同時に行います。その結果として、マルチCPU環境では、GC時間の減少、スループットの向上の効果が期待できます。パラレルGCを行うスレッド数は-XX:ParallelGCThreads=(デフォルトはCPU数)で指定できます。同様の処理なのですが、一緒に利用できるオプション制限が異なります。下のコンカレントGCと一緒に利用できるのは、-XX:+UseParNewGCの方だけです。2つのオプションのどちらを使うかは、アプリケーションの実行時に実際に試して比較するのがよいでしょう。パラレルGCの仕組みまた、JVMには-XX:AggressiveHeapというオプションもあり、システムに応じて自動的に大規模なアプリケーションに適した設定を行ってくれます。XX:UseParallelGCが設定されます。-XX:AggressiveHeapは取りあえず、大規模用のサーバなどで試すのによいかもしれませんが、JVMのバージョンによって挙動は異なる可能性があります。コンカレントGC(JVMオプション:-XX:+UseConcMarkSweepGC)標準のGCではOld世代領域のGC期間中ずっとアプリケーションスレッドは停止していましたが、このGCではGC処理の多くをアプリケーションと並行に処理されます。従って一部の処理のときだけアプリケーションスレッドを停止するため、アプリケーションの停止時間を短くできます(Old領域内のオブジェクトに対しては必要になるまでコンパクト化は行われません)。コンカレントGCの仕組み本来GCは人がメモリ管理を意識しない間に適切に動作することが理想的です。GCは常に進化している技術であり、将来的にはアプリケーションに応じてヒープサイズの調節や、適切なGCの選択をJVMが自動的に行うようになるかもしれません。現時点ではGCのアルゴリズムを理解し、アプリケーションの動作中GCの様子を観察しながら、適切なGC選択、ヒープサイズの調整を行うことが、安定したパフォーマンスの良いアプリケーション作成の手助けとなるでしょう。せいじ)横河・ヒューレット・パッカード(株)(現日本ヒューレット・パッカード(株))に入社後、HP-UX上の日本語環境ソフトウェアの開発に従事。(ATR)へ出向し、人とシステムのインタラクションに関する研究を行う。その後、2000年問題対応のため品質管理を経験し、現在HP-UX技術コンサルティングに従事。デバイスドライバ開発サポートや、Javaプラットフォームパフォーマンスチューニングを中心に活動中。Framework)」(ピアソン・エデュケーション)がある。Edge」の執筆を担当している。メールマガジンをご購読ください。申し込みページへITmediaはアイティメディア株式会社の登録商標です。