4 ガベージ・コレクションのパフォーマンスに影響する要因
ガベージ・コレクションのパフォーマンスに影響する最も重要な2つの要因は、使用可能なメモリー総量と若い世代用のヒープの割合です。
ヒープの合計サイズ
ガベージ・コレクションのパフォーマンスに影響する最も重要な要因は、使用可能なメモリーの総量です。コレクションは世代がいっぱいになると発生するので、スループットは使用可能なメモリーの量に反比例します。
ノート:
次に示すヒープの拡大と縮小、ヒープ・レイアウトおよびデフォルト値に関する説明は、例としてシリアル・コレクタを使用しています。他のコレクタが同様のメカニズムを使用しても、ここで示される詳細は他のコレクタに当てはまらないことがあります。他のコレクタに関する同様の情報は、それぞれのトピックを参照してください。
世代サイズに影響するヒープ・オプション
世代サイズに影響するオプションはたくさんあります。図4-1は、ヒープ内のコミットされた領域と仮想領域の違いを示しています。仮想マシンの初期化時に、ヒープの全体領域が確保されます。確保する領域のサイズは、-Xmx
オプションで指定できます。-Xms
パラメータの値が-Xmx
パラメータの値よりも小さい場合、確保されている領域の一部がただちに仮想マシン用にコミットされます。この図では、コミットされていない領域は「Virtual」と示されています。ヒープのそれぞれの部分(古い世代と若い世代)は、必要に応じて、仮想領域の制限までサイズを大きくすることができます。
パラメータのいくつかは、ヒープのある部分と他の部分の比率です。たとえば、パラメータ–XX:NewRatio
は、古い世代の若い世代に対する相対サイズを示します。
ヒープ・サイズのデフォルト・オプションの値
デフォルトで、コレクションが発生するたびに、ライブ・オブジェクトに対する空き領域の割合が一定範囲内に保たれるように、仮想マシンによってヒープが拡大/縮小されます。
この対象範囲は-XX:MinHeapFreeRatio=
<minimum>オプションと-XX:MaxHeapFreeRatio=
<maximum>オプションでパーセント値として設定され、合計サイズは下限値–Xms
<min>
と上限値–Xmx
<max>
によって制限されます。64ビットSolarisオペレーティング・システム(SPARC Platform Edition)用のデフォルト・オプションを表4-1に示します。
表4-1 64ビットSolarisオペレーティング・システム用のデフォルト・オプション
オプション | デフォルト値 |
---|---|
-XX:MinHeapFreeRatio |
40 |
-XX:MaxHeapFreeRatio |
70 |
-Xms |
6656KB |
-Xmx |
計算 |
これらのオプションを使用した場合、世代の空き領域の割合が40%を下回ると、40%の空き領域を維持するように、世代の最大許容サイズを上回らない範囲で世代のサイズが拡大されます。同様に、空き領域の割合が70%を超えると、空き領域が70%以下になるように、世代の最小サイズを下回らない範囲で世代のサイズが縮小されます。
表4-1に示されているように、デフォルトの最大ヒープ・サイズはJVMで計算される値です。Java SEのパラレル・コレクタで使用されていた計算は、すべてのガベージ・コレクタで使用されるようになりました。64ビット・プラットフォームの最大ヒープ・サイズの上限の計算も含まれます。「パラレル・コレクタのデフォルト・ヒープ・サイズ」を参照してください。クライアントJVMにも同様の計算があり、サーバーJVMよりも最大ヒープ・サイズが小さくなります。
サーバー・アプリケーションのヒープ・サイズに関する一般的なガイドラインを次に示します。
-
一時停止が問題になっていなければ、できるだけ多くのメモリーを仮想マシンに割り当てます。多くの場合、デフォルトのサイズは小さすぎます。
-
-Xms
と-Xmx
を同じ値に設定すると、サイズについての最も重要な決断を仮想マシンが行う必要がなくなり、予測性が高まります。ただし、ユーザーの選択が不適切であった場合に、仮想マシンでは調整できません。 -
一般に、割当ては並列化できるので、プロセッサ数を増やすにつれて、メモリーも増やしてください。
Javaヒープ・サイズの最小化による動的フットプリントの節約
アプリケーション用の動的メモリー・フットプリント(実行中に消費される最大RAM)を最小化する必要がある場合、Javaヒープ・サイズを最小化することにより、これを実行できます。Java SE Embeddedアプリケーションは、これを行う必要があります。
Javaヒープ・サイズを最小化するには、コマンド行オプション-XX:MaxHeapFreeRatio
および-XX:MinHeapFreeRatio
を使用して、オプション-XX:MaxHeapFreeRatio
(デフォルト値は70%)および-XX:MinHeapFreeRatio
(デフォルト値は40%)の値を小さくします。-XX:MaxHeapFreeRatio
を10%程度小さくして-XX:MinHeapFreeRatio
を小さくすると、パフォーマンスが大幅に低下することなく、ヒープ・サイズが正常に削減されることが示されます。ただし、アプリケーションによって結果は異なることがあります。これらの値が可能なかぎり低くなり、許容できるパフォーマンスを維持するように、様々な値を試してください。
さらに、-XX:-ShrinkHeapInSteps
を指定して、即座にJavaヒープをターゲット・サイズに削減することもできます(パラメータ-XX:MaxHeapFreeRatio
により指定)。これを設定すると、パフォーマンスが低下する場合があります。デフォルトでは、JavaランタイムでJavaヒープをターゲット・サイズに徐々に削減します。このプロセスには複数のガベージ・コレクション・サイクルが必要になります。
若い世代
使用可能なメモリー総量に次いで、ガベージ・コレクションのパフォーマンスに影響する重要な要因は、若い世代用のヒープの割合です。
若い世代のサイズが大きいほど、マイナー・コレクションが発生しにくくなります。ただし、ヒープのサイズには制限があるので、若い世代を大きくすると、古い世代が小さくなり、メジャー・コレクションが発生しやすくなります。最適な選択は、アプリケーションによって割り当てられるオブジェクトの寿命分布に左右されます。
若い世代のサイズ・オプション
デフォルトでは、若い世代のサイズはオプション-XX:NewRatio
で制御します。
たとえば、-XX:NewRatio=3
と設定すると、若い世代と古い世代の比率が1:3になります。つまり、Eden領域とSurvivor領域の合計サイズが、合計ヒープ・サイズの1/4になります。
オプション-XX:NewSize
と-XX:MaxNewSize
では、若い世代の下限値と上限値を設定します。これらを同じ値に設定すると、若い世代のサイズが固定されます(-Xms
と-Xmx
を同じ値にすると、合計ヒープ・サイズが固定されるのと同じです)。これは、-XX:NewRatio
で許可されている整数倍よりもきめ細かく若い世代を調整できるので便利です。
Survivor領域のサイズ設定
オプション-XX:SurvivorRatio
を使用すると、Survivor領域のサイズを調整できますが、これはパフォーマンスの点でそれほど重要にはなりません。
たとえば、-XX:SurvivorRatio=6
と設定すると、Eden領域とSurvivor領域との比率が1:6になります。つまり、各Survivor領域のサイズはEden領域の1/6、すなわち若い世代の1/8になります(Survivor領域は2つあるので、1/7にはなりません)。
Survivor領域が小さすぎると、コピー方式コレクションがオーバーフローして、古い世代に直接送られてしまいます。Survivor領域が大きすぎると、使用されない領域が無駄になります。仮想マシンは、ガベージ・コレクションのたびに、しきい値(古い世代に送るまでにオブジェクトをコピーできる回数)を選択します。このしきい値は、Survivor領域の使用率を半分以下に抑えるように選択されます。このしきい値と、新しい世代のオブジェクトの年齢を表示するには、ログ構成-Xlog:gc,age
を使用できます。これは、アプリケーションの寿命分布を確認する場合にも役立ちます。
表4-2に64ビットSolarisのデフォルト値を指定します。
表4-2 Survivor領域のサイズ設定のデフォルト・オプション値
オプション | デフォルト値 |
---|---|
|
2 |
|
1310MB |
|
無制限 |
|
8 |
若い世代の最大サイズは、ヒープ総量の最大サイズと-XX:NewRatio
パラメータの値から計算されます。-XX:MaxNewSize
パラメータのデフォルト値「無制限」は、コマンド行で-XX:MaxNewSize
に値を指定しないかぎり、計算値は-XX:MaxNewSize
で制限されないことを意味しています。
サーバー・アプリケーションの一般的なガイドラインを次に示します。
-
最初に、仮想マシンに割り当てる余裕のある最大ヒープ・サイズを決定します。次に、若い世代のサイズに対する独自のパフォーマンス・メトリックをグラフにして、最適な設定を求めます。
-
最大ヒープ・サイズは、マシンに搭載されたメモリー容量よりも必ず小さくして、過剰なページ・フォルトやスラッシングの発生を回避する必要があります。
-
-
合計ヒープ・サイズが固定されている場合、若い世代のサイズを増やすには、古い世代のサイズを減らす必要があります。アプリケーションによって一定期間使用されるすべてのライブ・データを保持するのに十分な大きさと、ある程度の余分な領域(10%から20%以上)を古い世代に確保します。
-
前に説明した古い世代の制約に従います。
-
十分な量のメモリーを若い世代に割り当てます。
-
割当ては並列化できるので、プロセッサ数を増やすにつれて、若い世代のサイズも大きくしてください。
-