ガベージ コレクション (GC) チューニング ガイド
GC パフォーマンス チューニングでできないこと
GC パフォーマンスのチューニングだけですべてをまかなうことはできません。環境のパフォーマンスの上限に到達した場合など、変更を加えてもこれ以上成果が得られなくなるポイントがあります。まだ目標に到達していないのにこれが発生した場合は、より強力なハードウェアの取得、OS のチューニングやアプリケーションのチューニングなど、GC チューニング以外の変更を検討する必要があります。
また、明示的なチューニングを提供することで、実際にパフォーマンスを低下させる場合があることに注意してください。アプリケーションを継続的に監視し、チューニングの元となった推測がまだ保留になっていることを確認することが重要です。
1. パフォーマンス目標の選択
GC パフォーマンス チューニングを行うためには、最初に目標を選択する必要があります。次の手順では、GC チューニング用にシステムを準備する際に、これらの目標に対する値を設定します。
In this section:
GC パフォーマンスの目標
Oracle HotSpot VM を使用したガベージ コレクションは、次の 3 つの目標まで減らすことができます。
- レイテンシ — ガベージ コレクションを実行する際に JVM によって誘発された休止。
- スループット— JVM がアプリケーションの実行に使用可能な実測時間ノパーセンテージ。
- フットプリント — 割り当てられたヒープ。
レイテンシ
レイテンシは、アプリケーションのユーザーがクエリの応答を待機する時間の一部です。例:JIRA ダッシュボードへのアクセスや、課題の検索。具体的に言うと、GC チューニングの場合、Jira が休止して、アプリケーションを実行できない時間です。主な測定値には、平均 GC レイテンシと最大レイテンシの 2 つがあります。平均レイテンシは通常の GC 休止を示し、最大レイテンシは予想される最大休止時間を示します。この目標のモチベーションは通常、応答性ではなく、クライアントが認識するパフォーマンスに関連します。もう一つ考慮すべきなのは、別のシステムがアプリケーションのクエリに追加されていて、接続のタイムアウトや処理遅延により他のシステムに影響を与える場合です。
レイテンシは秒単位で表されます。チューニングの目的では、レイテンシには次の 2 つの主な目標があります。
- 平均休止時間
- 最大休止時間
スループット
スループットとは、アプリケーションの実行に使用できる時間のパーセンテージです。アプリケーションを実行可能な時間が増えると、サービス リクエストに使用可能な処理時間も増えます。高いスループットと低いレイテンシは必ずしも関連しているわけではありません。— 高いスループットには稀に、長い休止時間が伴う場合があります。
フットプリント
フットプリントは、JVM がアプリケーションを実行するために消費するメモリの量です。このことは通常、メモリ上の制約がある環境の場合に重要です。
Oracle HotSpot VM ガベージ コレクションの原則
目標に到達するため、HotSpot VM for GC パフォーマンス チューニングに関するガイダンスを提供する 3 つの原則があります。
- マイナー GC の再利用 — マイナー GC の再利用コストが少なくて済む
- GC がメモリを最大化する— メモリは多いほど「良い」
- 3 つのうち 2 つ — 3 つのパフォーマンスの目標のうち 2 つを選択する
マイナー GC の再利用
これは、次のように想定される、世代間のガベージ コレクションが前提となっています。
- ほとんどのメモリ割り当ては存続期間が短い。
- ほとんどの古いオブジェクトは古いオブジェクトのみを参照する。
- ほとんどの古いオブジェクトは存続期間が長い。
- GC 収集コストは、オブジェクトの存続期間のセットに比例する。
大多数のアプリケーションでは、ほとんどのガベージは存続期間が短い最近のオブジェクト アプリケーションから作成されます。
この一連の推測は、新しい割り当てに対するメモリ領域と古い割り当てに対するメモリ領域の間で GC の作業を分割するとより効率的であることを示しています。新しい領域 (または世代) では、最後にライブ オブジェクトが少ない場合により早く処理できますが、古い世代は一般的に、収集の最後でのライブ オブジェクトがより多くなります。
これが意味すること
新しい世代から古い世代へ進んだ、または続いている存続期間の短い割り当てが減り、逆に、新しい世代から古い世代へ続く存続期間の長い割り当てが増えると、JVM 全体的なガベージ コレクション効率がより高くなります。これにより、スループットが高くなります。
GC がメモリを最大化するという原則
メモリが無限にある場合は、ガベージを収集する必要はありません。
JVM に割り当てるメモリが増えると、収集の頻度は少なくなります。つまり、存続期間の短いオブジェクトの作成率によりうまく対応できるよう、新しい世代を適切なサイズにすることができます。これにより、古い世代に進めるアプリケーションの数が減ります。
3 つの原則のうちの 2 つ
簡単に進めるため、パフォーマンスの目標を 2 つだけ選択し、それ以外を犠牲にすることをお勧めします。より簡単にするには、目標を 1 つに絞ります。目標というものは、競合していることが良くあります。たとえば、スループットを向上させるためにヒープに割り当てるメモリを増やす場合、平均休止時間が短くなる可能性が高くなります。逆に、ヒープに割り当てるメモリを減らすことで平均休止時間を減らすと、停止の頻度も増加し、スループットが削減する可能性が高くなります。ヒープ サイズ設定と同様に、すべての世代のメモリとサブ世代のエリアのサイズが適切で、より優れたレイテンシとスループットを提供する場合は通常、JVM フットプリントが犠牲になります。
言い換えれば、GC のチューニングとはバランスをとることです。GC チューニングだけではすべての目標を達成できない場合があります。
2. GC チューニング用に環境を整える
目標を選択したら、GC チューニング用に環境を整える必要があります。この手順の成果は、選択した目標に対する値となります。目標と値の 2 つをまとめたものが、チューニング対象となる環境のシステム要件になります。
In this section:
アプリケーションに作業をロードする
特定のアプリケーションを実行する JVM の GC パフォーマンスを測定する前に、アプリケーションに作業を実行させ、定常状態に到達できる必要があります。アプリケーションに負荷を適用することで、これを実行できます。アプリケーションへの作業のローディングは本ガイドの範囲ではありません。負荷は、GC のチューニングを行う準備状態の負荷に基づいてモデル化することを強くお勧めします (例: アプリケーションを本番環境で使用したときに予想される使用状況パターンと数量を反映した負荷など)。
JVM チューニング パラメーターを繰り返し変更することが必要がなる可能性があります。主にチューニングでのエラーをなくし、ユーザーに与える混乱を最小限に抑えるため、できるだけ本番環境に近い環境で実行することをお勧めします (例: 類似したハードウェア、OS バージョン、ロード プロファイルなど)。このプロセスでは、望ましい結果を達成するために、何回も繰り返す必要が出る場合があります。そのため、システムが既に本番環境になっている場合、ユーザーに与える混乱を検討する価値があります。
GC ログ作成をオンにする
Oracle VM のみ
次の JVM パラメーターは Oracle 1.6 JVM 専用です。その他の実装では、これらの固有パラメーターを共有しない場合があります。
詳細は、JVM ドキュメントを参照してください。
JVM の GC パフォーマンスを測定するには、GC ログ作成をオンにする必要があります。これは、スタートアップ時、JVM に渡されるコマンドライン フラグ経由で実行されます。例:
java -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:<file> …
GC 診断をアプリケーション ログから切り離すには、別の GC ログ ファイルを使用することを強くおすすめします。VM 起動以降のオフセットではなく、日付と時刻が含まれるタイムスタンプを希望する場合は、-XX:+PrintGCDateStamps
を使用します。
また、GC ログ ファイルの場所には、$JIRA_HOME/log
ディレクトリ (インストールの絶対パスまで展開) を使用することをお勧めします。これにより、ログ ファイルがサポート ZIP に自動的に含まれます。
データ サンプリング ウィンドウを設定する
GC ログのサンプリング ウィンドウを確認する際には、これらの期間が、チューニング対象のターゲット負荷でアプリケーションが操作された時期を表すことが重要です。さらに、アプリケーションと JVM がこれらの定常状態に到達するために、ある期間が必要な場合もあります。例えば、サービス リクエストに対する準備が整うまでアプリケーションが自動実行するのに数分かかったり、すべての長寿命キャッシュに送られるまで 30 分ほどかかる場合があります (メモリー フットプリントの一部となるため)。
チューニング対象となる環境でのアプリケーションの定常状態を表す間隔については、自分自身で判断する必要があります。
メモリ フットプリントのを決定する
JVM 世代のサイズをチューニングするため、定常状態のライブ データ セット サイズを良く知っておく必要があります。これは、2 つのうちいずれかの方法で取得できます。
推測する
GC ログから取得
これは、VM で現在アプリケーションを実行でき、定常状態に到達していることを前提としています。これができない場合は、以下を試してください。
メモリをディスクにスワップさせることなく、可能な限り最大限のヒープ サイズを JVM に与える。
スループット コレクター (
-XX:+UseParallelOldGC
) を既定パラメーターとともに使用する。
JVM を実行し、メモリ関連のエラー (java.lang.OutOfMemoryError
など) がないことを確認します。メモリ関連のエラーがあり、ヒープに可能な限りのメモリが割り当てられていると考えられる場合、システム メモリの量を増やすなど、JVM 外部のパラメータを変更する必要があります。
アプリケーションを安定状態で実行したら、フル GC 後の古い世代と永続世代の平均専有率からメモリのフットプリントを推定する必要があります。GC 後の古い世代と永続世代の専有率をそれぞれ ^
と +
で表した、フル GC のログ行の例は次の通りです。
773.192: [Full GC [PSYoungGen: 299756K->0K(6552704K)] [ParOldGen: 11486930K->6622879K(11657024K)] 11786686K->6622879K(18209728K) [PSPermGen: 161761K->160673K(247808K)], 43.4385540 secs] [Times: user=181.10 sys=1.68, real=43.44 secs]
^^^^^^^ ++++++
あらゆる定常状態期間の、これらのフィールドの平均 (古い世代と永続世代の平均フットプリント) を見つけます。
たとえば、1 つの時間枠を使用して、次のフル GC 行から、300 秒を 3600 秒間でオフセットします:
287.223: [Full GC [PSYoungGen: 682071K->0K(9521152K)] [ParOldGen: 1709104K->862326K(1929728K)] 2391175K->862326K(11450880K) [PSPermGen: 164815K->164809K(262144K)], 1.3367950 secs] [Times: user=7.12 sys=0.07, real=1.34 secs]
1125.789: [Full GC [PSYoungGen: 1069485K->0K(10115264K)] [ParOldGen: 2026464K->1577765K(2659264K)] 3095949K->1577765K(12774528K) [PSPermGen: 165949K->165940K(262144K)], 2.9698460 secs] [Times: user=14.42 sys=0.04, real=2.97 secs]
2204.512: [Full GC [PSYoungGen: 1026559K->0K(10101568K)] [ParOldGen: 2710240K->1757747K(2980288K)] 3736799K->1757747K(13081856K) [PSPermGen: 166249K->166242K(262144K)], 3.2056200 secs] [Times: user=15.50 sys=0.02, real=3.21 secs]
2265.623: [Full GC [PSYoungGen: 410046K->0K(10115584K)] [ParOldGen: 2762176K->1926377K(3520000K)] 3172222K->1926377K(13635584K) [PSPermGen: 166243K->166242K(262144K)], 4.1453870 secs] [Times: user=20.11 sys=0.03, real=4.14 secs]
2312.878: [Full GC [PSYoungGen: 580541K->0K(10115520K)] [ParOldGen: 3448192K->2398541K(4246336K)] 4028733K->2398541K(14361856K) [PSPermGen: 166243K->166243K(262144K)], 5.0057740 secs] [Times: user=25.06 sys=0.03, real=5.01 secs]
2406.074: [Full GC [PSYoungGen: 442182K->0K(9997056K)] [ParOldGen: 4059865K->2220928K(4308544K)] 4502047K->2220928K(14305600K) [PSPermGen: 166245K->166244K(262144K)], 4.6421270 secs] [Times: user=22.88 sys=0.04, real=4.65 secs]
2492.633: [Full GC [PSYoungGen: 551513K->0K(10058560K)] [ParOldGen: 4035620K->2219019K(4526080K)] 4587134K->2219019K(14584640K) [PSPermGen: 166249K->166249K(251264K)], 4.4630140 secs] [Times: user=22.36 sys=0.01, real=4.46 secs]
2551.866: [Full GC [PSYoungGen: 757661K->0K(9941888K)] [ParOldGen: 4285737K->2455810K(4991616K)] 5043398K->2455810K(14933504K) [PSPermGen: 166259K->166258K(239424K)], 4.5891680 secs] [Times: user=23.50 sys=0.03, real=4.59 secs]
2587.593: [Full GC [PSYoungGen: 180557K->0K(10140096K)] [ParOldGen: 4554339K->2111979K(4954688K)] 4734896K->2111979K(15094784K) [PSPermGen: 166264K->166264K(229056K)], 4.5708050 secs] [Times: user=22.55 sys=0.02, real=4.57 secs]
2717.263: [Full GC [PSYoungGen: 286857K->0K(9503424K)] [ParOldGen: 4726275K->2537156K(5506560K)] 5013132K->2537156K(15009984K) [PSPermGen: 166271K->166271K(219712K)], 6.0445180 secs] [Times: user=28.51 sys=0.03, real=6.04 secs]
2794.947: [Full GC [PSYoungGen: 601040K->0K(9763968K)] [ParOldGen: 5454180K->2849912K(6176064K)] 6055221K->2849912K(15940032K) [PSPermGen: 166272K->166272K(211968K)], 6.1950910 secs] [Times: user=30.35 sys=0.05, real=6.20 secs]
2841.383: [Full GC [PSYoungGen: 544562K->0K(10043968K)] [ParOldGen: 5736088K->3054858K(6731904K)] 6280651K->3054858K(16775872K) [PSPermGen: 166274K->166273K(204800K)], 6.5399570 secs] [Times: user=32.23 sys=0.04, real=6.54 secs]
6663.915: [Full GC [PSYoungGen: 1080358K->0K(10062592K)] [ParOldGen: 6735458K->2460384K(5908544K)] 7815817K->2460384K(15971136K) [PSPermGen: 166399K->166398K(199168K)], 7.2638840 secs] [Times: user=29.06 sys=0.06, real=7.27 secs]
古い世代と永続世代の平均:
世代 | 平均 |
---|---|
古い | 2282735 KB |
永続 | 166227 KB |
この場合、注意点があります。JVM 内で実行しているアプリケーションがキャッシュを積極的に作成し、このキャッシュ サイズがヒープ サイズまたは古い世代のサイズに比例している場合、ヒープ サイズまたは古い世代が増えると、古い世代の平均サイズは大きくなる可能性が高くなります。このため、キャッシュによってヒープ サイズが急増します。
世代のサイズに関する経験則
メモリ フットプリントに基づいた、異なる世代のサイズ設定には、さまざまな経験則があります。
最大ヒープ サイズは古い世代のサイズx 3x – 4 の間にする必要がある。
古い世代は、古い世代の平均 x 1.5 以上にする必要がある。
永続世代は、永続世代の平均x 1.5 以上にする必要がある。
新しい世代はヒープ全体の 10% 以上にする必要がある。このことは、新しい世代のサイズを手動で設定する場合にのみ重要となる。
大部分が同時のガベージ コレクターに切り替える場合は、古い世代と永続世代のサイズを 20% 増やす必要がある (永続世代 CMS が有効化されていると想定する)。
JVM のサイズを再設定する際は、利用可能な物理メモリの量を超えないようにしてください (JVM によって消費されるメモリはヒープのみの場合よりも多くなります)。これにより、仮想メモリ スラッシングや、最悪の場合発生する JVM プロセスの終了を回避します。
初期ヒープ サイズの設定
これで、メモリ フットプリントが計算されました。次に、チューニング演習用に初期ヒープ サイズを設定できます。
GC パラメーター: | 値: | VM フラグ: |
---|---|---|
ヒープサイズ: | 4x 古い世代の平均 |
|
古い世代のサイズ: | 1.5x 永続世代の平均 |
|
メモリ フットプリントの例を使用した、初期ヒープ サイズ パラメーターの例:
-Xmx9130942K -XX:MaxPermSize=249340K
システム要件を決定する
パフォーマンスの目標では、VM GC チューニングのための 3 つのパフォーマンス チューニングの目標について説明しました。ここで、これらの目標の値を決定する必要があります。これらは、GC のパフォーマンスを調整する環境のシステム要件を表します。
決定を行うシステム要件の一例:
許容可能な平均マイナー GC 休止時間 (秒)
許容可能な平均フル GC 休止時間 (秒)
許容可能な最大フル GC 休止時間 (秒)
許容可能な最小スループット (時間のパーセンテージで表示)
一般的に、レイテンシやフットプリントの目標に焦点を当て、小さな値を希望する場合や、スループットの値を小さくして休止時間の最大許容値を設定する場合や、逆に、スループットに焦点を当てる場合、最大許容値なしで休止時間に大きな値を設定したり、スループットに大きな値を設定する方が良いことがあります。
ここで何が必要かをよく理解していなくても問題ありません。アプリケーションを手動でテストした後にいつでもチューニングをやり直し、チューニング環境内でのアプリケーションの応答性を決定することができます。
初期ヒープ サイズの例に続いて、2 セットの合成システム要件を例でさらに使用します。
スループット用の合成システム要件:
システム要件: | 値: |
---|---|
許容可能な平均マイナー GC 休止時間: | 0.20 秒 |
許容可能な平均フル GC 休止時間: | 30.0 秒 |
許容可能な最小スループット: | 90% |
レイテンシ用の合成システム要件:
システム要件: | 値: |
---|---|
許容可能な平均マイナー GC 休止時間: | 0.10 秒 |
許容可能な最大フル GC 休止時間: | 10.0 秒 |
許容可能な最小スループット: | 65% |
3. スループット コレクターと動作ベースのチューニングについて理解する
一般に、アトラシアン製品の GC シナリオの大部分は、Oracle HotSpot VM のスループット コレクタ (-XX:+UseParallelOldGC
) を使用して解決できます。ただし、厳格な最大許容停止時間や非常に高いスループットが必要な場合、手動でのチューニング (本ガイドの範囲外) が必要となります。
ほとんどの GC シナリオを解決するため、HotSpot VM では並列コレクターを使用した動作ベースのチューニング (Mostly-Concurrent Mark-Sweep コレクターを含む) を採用しています。 並列コレクターはチェック中の 3 つの目標を保持するために設計されています。これらの目標は次のとおりです (優先度の降順):
- 最大休止時間
- スループット
- フットプリント
これらの動作はパフォーマンス目標にマッピングされます。このような目標は、各コレクションで優先度順に評価されます。目標が達成されていないと判定されると、その失敗した目標を達成できるようにヒープ サイズが調整され、残りの目標はそのコレクションでは評価されません。この動作を観察する場合は、JVM に -XX:+PrintAdaptiveSizePolicy
コマンド ライン フラグを使用します。
In this section:
動作ベースのチューニングの目標
最大休止時間の目標
最大休止時間の目標を使用して、各世代 (新しい世代と古い世代) は平均休止時間値を追跡し、この目標を超えた場合、 特定の世代のサイズが縮小されます。既定の最大休止時間の目標は設定されていません。最大休止時間の目標を設定するため、次のフラグを独立して使用できます (マイナー収集とフル収集の休止時間の目標が異なる場合は両方を設定する)。
マイナー収集とフル収集の両方の場合: | -XX:MaxGCPauseMillis=<n> |
マイナー収集のみの場合: | -XX:MaxGCMinorPauseMillis=<n> |
これらは、任意の GC イベントに対する最大休止時間を保証するものではありません。
スループットの目標
スループットの目標は、新旧両方の世代のコレクションの単一測定です。スループットは、VM 内でガベージ コレクションの実行に費やした時間に対して VM がアプリケーションを実行するのに費やした時間のパーセント値として決定します。この目標に到達しない場合、値の大きい世代のほうが達成に時間がかかると見なし、世代サイズが増やされます。既定の目標はアプリケーション時間の 99 %、GC 時間の 1% です。-XX:GCTimeRatio=<n>
を参照してください。この、アプリケーション時間に対する GC 時間の割合を決定する式は次のとおりです。
f(n) = 1 / (1 + n)
ここで、n は目標のアプリケーション時間 (パーセント値) です。既定値 99
を代入すると以下のようになります。
f(99) = 1 / (1 + 99)
= 1 / (100)
= 0.01
= 1%
次のグラフは、GCTimeRatio
、結果のスループットの目標、およびすべての GCTimeRatio
値に対するスループットの割合を表示する Python スクリプト間の関係を表しています。
def f(x):
return 1 - (1 / (1.0 + x))
i = 1
while i <= 99:
print "%d\t%.02f %%" % (i, f(i) * 100)
i += 1
休止時間を測定した際と同様に、ヒープのサイズを再設定する前の平均加重スループットに対してスループットの目標が計算されます。
フットプリントの目標
フットプリントの目標について、過去の 2 つの目標が達成された場合、ガベージ コレクタはそれらのいずれかが満たされなくなるまでヒープ サイズを減らします。これは、最大サイズと最小サイズを明示的に同じ値に設定することでヒープ サイズが修正されていないことを前提としています (例: -Xms<n>[g|m|k] -Xmx<n>[g|m|k]
)。
目標間の相互作用
動作ベースのチューニングでは以下を念頭に置いているため、目標が達成されていない場合には GC パラメーターを調節することを目標にします。たとえば、最大休止時間の目標の場合、世代の加重平均休止時間がこの値を上回るまで、その世代のサイズは変更されません。そのため、動作ベースのチューニングがヒープサイズの減少を開始するには、許容可能な最大フル GC 休止時間を上回る場合があります。
スループットの目標は常にあるため、休止時間が長くなりすぎないようヒープ サイズを縮小した場合、(既定のスループットの目標では) 次のコレクションでスループットの目標を達成しようと試みるため、ヒープ サイズが増やされる可能性が高くなります。これによって、最終的に、最大休止時間の目標を再度達成できず、スループット コレクターがこれらの 2 つの目標の達成の間を往復することになる場合があります。
4. チューニングを行う時間です!
この段階までに、次の準備を行っています。
- 負荷を生成できる。
- 何のためにチューニングを行うかがわかっている。
- 初期ヒープ パラメーターを持っている。
- スループット コレクターを選択した。
これらの準備が整ったら、チューニングを開始します。
一般的に、GC チューニングのワークフローは次のように機能します。
- 希望する動作を指定する。
- 変更を加える前に動作を測定する。
- 表示されている変更を決定する。
- 変更を加える。
- 変更後の動作を測定する。
- 動作が不十分な場合は、再試行する。
以下の手順では、最初に GC パフォーマンス (レイテンシ、スループット) を測定します。次に、それをシステム要件と比較します。最後に、要件を満たすための再チューニング方法の例をいくつか提供します。
In this section:
レイテンシの計算
マイナー GC レイテンシの計算
上記で提案した GC ログ作成とともにスループット コレクターを使用する場合、マイナー GC イベントは次のようになります。
37.668: [GC [PSYoungGen: 5245632K->167562K(6119872K)] 5245632K->167562K(17776832K), 0.0840040 secs] [Times: user=1.05 sys=0.11, real=0.08 secs]
^^^^^^^^^
フル GC レイテンシの計算
GC ログ作成フラグが同じであれば、フル GC イベントは次のようになります (ここでも、関係するフィールドには '^' 文字で下線が付きます):
773.192: [Full GC [PSYoungGen: 299756K->0K(6552704K)] [ParOldGen: 11486930K->6622879K(11657024K)] 11786686K->6622879K(18209728K) [PSPermGen: 161761K->160673K(247808K)], 43.4385540 secs] [Times: user=181.10 sys=1.68, real=43.44 secs]
^^^^^^^^^^
スループットの測定
アプリケーション スループット (アプリケーションを同時に実行するためにJVM を利用できる時間の %) はある程度複雑ですが、基本的には、VM が休止されない、指定されたサンプル ウィンドウに対する時間のパーセンテージです。GC ログはこれを直接提供しませんが、すべての GC イベントに対して経過した時間のパーセンテージを決定することで計算できます (マイナーおよびフル)。 スループット コレクターでは、各 GC イベントの合計所要時間は、VM が休止され、アプリケーションを実行していない期間を示しますが、指定したサンプル ウィンドウに対して必要な操作は、各マイナーまたはフル GC イベントの期間を合計するだけです。
上記の「平均マイナー GC レイテンシの計算」および「最大フル GC レイテンシの計算」の GC ログの例はすでに、休止期間を表すフィールドを示しています。
測定値とシステム要件の比較
これで、GC パフォーマンスの特性が測定されました。次に、これらをシステム要件と比較することができます。スループット コレクターの既定のチューニングでシステム要件がm地アされない場合は適宜、チューニング パラメーターを設定して負荷テストを再実行します。もう一度点検し、結果に問題がなければ完了です。
ただし、結果がまだ要件を満たしていない場合は、いくつかのオプションがあります。
- 要件のレビューを行う。必要に応じて変更を加え、再テストを実施する。
- ファクターを外部から JVM ガベージ コレクションに変更する。例:
- より多くの/高速な RAM。
- より多くの/高速な CPU コア。
- 新しくサポートされた JVM のバージョン。
- JVM で実行されるアプリケーションの変更。
- より細かい GC チューニングを実行する (より詳細な別のチューニング ガイドに記載)。詳細なガイドでは、ヒープ サイズと世代のサイズ、古いしきい値、Mostly Concurrent Mark-Sweep コレクターの使用、およびプラットフォーム/環境特有のチューニング パラメーターの操作についてさらに詳しく説明しています。
上記の合成要件から生じた、既定の動作チューニング パレメーターを使用した負荷テストの例の GC パフォーマンス測定値は次のようになります (「ガベージ コレクション (GC) チューニング ガイド」を参照,。オフセット 300 秒、サンプル ウィンドウ 900 秒間を使用):
平均マイナー GC 休止時間: | 0.13 秒 |
最大フル GC 休止時間: | 3.58 秒 |
スループット: | 88.27 % |
これらの測定値から、レイテンシとスループットのいずれの目標も完全には達成されていません。そのため、動作ベースのチューニング パラメーターを必要に応じて変更し、テストを再実行する必要があります。
スループットの再チューニングの例
再調整後のサンプリング時間枠内に測定されたスループット値は、必要な値よりも少なくなります。既定のスループット目標がアプリケーション スループットの 99 % で、サンプリング時間内に到達したのが 88.27 % の場合、構成されたヒープ パラメーターでは目標を達成できないということを示します。私たちは現在、「測定値とシステム要件の比較」で提案したような選択肢に直面しています。手動チューニング オプションで目標を達成しようとさらに試みるのが理想的ですが、これは本ガイドの範囲外のため、要件を再確認します。
たとえば、負荷テストを定常状態で実行中、テスト中のアプリケーションを手動で動かしたところ、応答性と認知されたスループットがシステムの利害関係者を十分満足させられることを示す場合があります。そのため、要件が下げられ、必要なパフォーマンス結果の達成に必要なレベルを要件が上回っていたことを示します。
レイテンシの再チューニングの例
この場合、スループットは必要な量よりも多く、最大フル GC 休止時間は最大許容値よりも少なくなっていますが、平均マイナー GC 休止時間は必要な制限に違反しています。この目標に対応するため、フル コレクションとマイナー コレクションと両方に対して休止時間を設定します。休止時間とスループット目標の間を近づけるため、スループットの目標は、結果のスループット パーセンテージが要件よりも大きくなる、最初の割合に留められます。結果の JVM オプションは次のようになります。
-XX:MaxGCPauseMillis=10000 -XX:MaxGCMinorPauseMillis=100 -XX:GCTimeRatio=2
新しい GC チューニング パラメーターを追加し、負荷テストを再実行した後、パフォーマンス測定値は次のようになります (「ガベージ コレクション(GC) チューニング ガイド」を参照、オフセット 300 秒、サンプル ウィンドウ 900 秒):
平均マイナー GC 休止時間: | 0.06 秒 |
最大フル GC 休止時間: | 5.33 秒 |
スループット: | 80.19 % |
これで、3 つのシステム要件がすべて満たされました。
ツール
Oracle HotSpot VM で GC パフォーマンスを解釈するための便利なツールがいくつかあります。そのうち、次の 2 つをお勧めします。
- Visual GC プラグイン搭載の Java VisualVM、ライブ GC テレメトリ用。JDK の
bin/
ディレクトリでjvisualvm
を確認するか、Web サイトにアクセスしてください。 - Chewiebug の GCViewer。このツールは、GC ログ ファイルに基づいて GC パフォーマンスの多重比較レビューに適しています。
参考文献
- C Hunt and B John、Java™ Performance、Addison-Wesley、2011
- Sun Microsystems、Memory Management in the Java HotSpotTM Virtual Machine、Sun Microsystems、2006、2012 年 3 月 14 日取得、<http://java.sun.com/j2se/reference/whitepapers/memorymanagement_whitepaper.pdf>
- Oracle Technology Network、Java HotSpot VM Options、Oracle Corporation、2012、2012 年 3 月 14 日取得、<http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html>
- Oracle Technology Network、Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning、Oracle Corporation、2012、2012 年 3 月 14 日取得、<http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html>
- OpenJDK、jdk/jdk6/hotspot、Oracle Corporation、2012、2012 年 3 月 14 日取得、<http://hg.openjdk.java.net/jdk6/jdk6/hotspot>