Java言語では、Javaオブジェクトに対するメモリ領域の割り当てや解放をJVM(Java仮想マシン)が自動的に行います。この自動解放メカニズムを「ガベージ・コレクション」と呼びます。ガベージ・コレクションは、Javaプログラムのパフォーマンスに決定的な影響を与えるため、その振る舞いを把握することがチューニング作業において極めて重要となります。そこで今回は、Javaのガベージ・コレクションの役割を説明し、ログの記録方法などを解説します。
Javaプログラムの実行中には、Javaオブジェクトが生成されます。Javaオブジェクトは、Javaプログラムの起動時に生成される場合もあれば、実行中に必要に応じて生成されることもあります。いずれの場合も、JVMの内部で新しいJavaオブジェクトが作成されると、「ヒープ」と呼ばれるメモリ領域に、同オブジェクトを格納するための領域が割り当てられていきます。
このヒープのサイズは、JVMの起動時にオプションで指定することができます。例えば、以下のコマンドは、ヒープの最大値を240Mbytesに制限してJVMを起動する例です。
$ java -Xmx240m <クラス名>
この場合、もしJVM内部で大量のJavaオブジェクトが生成され、そのサイズが240MBを超えると、JVMはエラー「OutOfMemoryError」を発してJavaプログラムの実行を停止します。
このように、すべてのJavaオブジェクトは、JVMのヒープの内部に順次格納されていきます。
Java言語では、ヒープ上のメモリ領域をJavaオブジェクトに割り当てたり、もしくは割り当て済みの領域を解放したりする処理を、プログラムコードに明示的に記述する必要がありません。これは、CやC++などの言語との大きな違いです。CやC++では、プログラムが使用するメモリ領域の割り当てや、使用済みの領域の解放を、プログラムコードから明示的に指示しなくてはなりません。
Java言語では、こうしたメモリ管理がJVMによって自動的に行われます。つまりJVMは、Javaプログラムのどこからも参照されなくなった不要なJavaオブジェクトを見つけ出し、そのメモリ領域を自動的に解放します。こうしたJavaオブジェクトの削除処理は「ガベージ・コレクション」と呼ばれます。JVM内部では、このガベージ・コレクションが独立したスレッドとして定期的に動作しています。ガベージ・コレクションが動作する頻度は、JVMのヒープ・サイズやヒープに対する需要、その他のさまざまな要因によって変化します。
ここで注意すべき点は、JVMがガベージ・コレクションを実行している間、ほかのすべてのスレッド(Javaプログラムを実行中のスレッドやJavaバイト・コードをコンパイル中のスレッドなど)の実行が停止してしまうことです。ガベージ・コレクションは、Javaプログラムのパフォーマンスに決定的な影響を与えるため、その振る舞いを把握することが極めて重要となります。
図1は、8個のCPUを搭載したマシン上で1つのJVMを実行し、ガベージ・コレクションの動作によるCPU負荷状態への影響を示したものです。同図に示されるように、ガベージ・コレクションによって高負荷状態となるCPUは1個だけであり、ほかのCPUはほぼアイドル状態となっています。このようにガベージ・コレクションは、Javaプログラム全体をスローダウンさせる大きな要因となります。
ガベージ・コレクションの挙動をコントロールするためには、JVM起動時のオプションを利用し、ヒープ・サイズなどを明示的に指定する必要があります。これについて詳しくは本連載で追って説明しますが、最初の一歩として、JVM内部でどの程度の頻度でガベージ・コレクションが発生しているかを把握することから始めます。
ガベージ・コレクションが頻繁に発生しているかどうかは、OSの管理ツールを通じてその手掛かりを得ることもできます。例えば図2のような突発的なCPU負荷上昇のパターンが見られる場合は、ガベージ・コレクションが必要以上に頻繁に発生している可能性が高いといえます。また同図を詳しく見ると、ユーザー時間が断続的に大きく落ち込んでおり、ガベージ・コレクションによってCPUリソースが有効に利用できていないことが分かります。
Copyright © ITmedia, Inc. All Rights Reserved.