Java VMパフォーマンスチューニングガイド

※気に入ったらアフェリエイトのクリックをお願い♪

■Introduction


1. チューニングの目的
2. チューニングポイント
3. まずは何もしないでGCを測定してみよう!
3.1. Summary
3.1.1. Heap Capacity
3.1.2. GC Activity Summary
3.1.3. Overall Statistics
3.2. Heap usage
3.3. Duration
3.4. User defined
4. アプリケーションに合わせたGCアルゴリズムを選択しよう
4.1. 「-server」オプションを試してみましょう。
4.2. 「-noclassgc」オプションを試してみましょう。
4.3. 「-XX:+UseParNewGC」を試してみましょう。
4.4. 「-XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=32」を試してみましょう。
5. Heapの最適値を探しましょう。
5.1. まずは、「-Xmx1024m」を設定してヒープの上限を見極めましょう。
5.2. 次に、ヒープのextensionを抑制してみましょう。
5.3. 「-Xmn32m」を試してみましょう。
5.4. 「-Xms128m -Xmn64m」を試してみましょう。
5.5. 「-Xmx1024m –Xms256m –Xmn128m」を試してみましょう。
6. 最後に


1. チューニングの目的


一般的に、チューニングを行う目的は実行時間を短くすることです。
本ドキュメントでも、実行時間を短くすることを目的にチューニングを行っています。


2. チューニングポイント


本ドキュメントでは、Java VMの起動オプションを変更することにより、実行速度の向上を実現します。
その際に必要なポイントとしては、以下のものがあります。
・GCアルゴリズムをアプリケーションにあったものにする。
・GC回数をなるべく減らす。
・GC時間をなるべく減らす。


3. まずは何もしないでGCを測定してみよう!


JavaVMのパフォーマンスチューニングを行う前に、まずは現在の状態を正確に把握しましょう。そうでないと、チューニングを行った結果、早くなったのか遅くなったのか判断出来ません。
というわけで、VMの起動オプションに「-Xloggc:」を付けて実行してみましょう。すると、GCログがに出力されます。このログをHPjtuneに読み込ませると、次のような画面が表示されます。
3.1. Summary

3.1.1. Heap Capacity
ここには、プログラムの最小Heap、最大Heapの情報が表示されます。物理メモリ量に余裕があるのなら、ここの値は、全て同じ値になる事が理想的です。
この場合ですと、初めに1.938MB、最大38.219MBを使用しています。その間に何回かHeapメモリの拡張が行われていると想像できます。
3.1.2. GC Activity Summary
GCについての情報が表示されます。気にすべきはCountと平均実行時間です。
この場合ですと、ScavangeGCが24138回、FullGCが9回実行されています。FullGCの実行時間を見ると、ScavangeGCの84倍時間がかかっている事が分かります。FullGCはコストが高いと言われている通りの結果です。なるべくFullGCが起こらないようにチューニングする必要があります。
3.1.3. Overall Statistics
合計実行時間[Duration Of the measurement]、GC使用率[Percent of time in GC]に注目します。
この場合ですと、GC使用率が赤くなっています。これは、GCが占有する時間が長すぎる、という意味で、Javaのメモリ管理をチューニングする余地がある、ということを意味しています。

3.2. Heap usage

この画面はHeapの使用量のグラフとなります。
初めの方にFull GCが頻繁に起こっています。これは、Heapの拡張が行われている為です。Heapの初期容量を増やせば、本GCは起こらなくなりますが、その話は後程。

3.3. Duration

このグラフはGCに使った時間を示しています。このグラフを見ると、1秒以上かかっているGCがあることが分かります。

3.4. User defined

本グラフはHeapサイズが拡張されたかどうかが分かります。Heapの拡張作業はコストがかかるので、なるべくなら拡張されないようにするのが望ましいです。


4. アプリケーションに合わせたGCアルゴリズムを選択しよう


VMでは、オプションで色々なGCアルゴリズムを選択出来るようになっています。それを変更することにより、GC処理が早くなる可能性があります。
取りあえず、アルゴリズムを変更してみます。

4.1. 「-server」オプションを試してみましょう。
付けて測定したところ、実行時間が419.365秒と短くなっていることが分かります。
本オプションはGCアルゴリズムを変更しています。ので、ヒープの使用方法には余り影響がなく、GCの実行回数や実行時間に影響があります。
では、一体何が早くなっているのでしょうか?詳しく見ていきましょう。

GC Activity Summaryを見ますと、Scanverge GC回数、Old full GC回数が減って、実行時間がわずかに減っていることが分かります。

GCの実行時間が短くなっています。全てのGCが1秒以内に終了しています。
本オプションは本プログラムでは効果があった事が分かります。

4.2. 「-noclassgc」オプションを試してみましょう。
付けて測定したところ、実行時間が382.006秒と短くなっていることが分かります。

GC Activity Summaryを見ますと、Other full GC回数が減って、実行時間が減っていることが分かります。つまり、「noclassgc」オプションはOther full GCに影響を与えるオプションである事が分かります。

GCの実行時間が短くなっています。全てのGCが0.2秒以内に終了しています。
本オプションは、本プログラムでは効果があった事が分かります。

4.3. 「-XX:+UseParNewGC」を試してみましょう。
付けて測定したところ、実行時間が385.86秒と長くなっていますが、GCの実行している時間は短くなっていることがわかります。微妙ですが、効果はありそうです。
本オプションをつけると、「Other Full GC」がなくなっていることが分かります。
本オプションは「Other Full GC」がなくなるという効果があるようです。



4.4. 「-XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=32」を試してみましょう。
付けて測定したところ、実行時間が1306.12秒と大変長くなっています。一体何が時間をくっているのでしょうか?
結果を見てみると、GC一回当たりの所用時間は0.1秒以下となっていますが、GCの回数が増えていることが分かります。
本検証を行った端末はシングルCPUの為、本オプションを付けてしまうと逆に遅くなってしまったのかもしれません。



5. Heapの最適値を探しましょう。


GCアルゴリズムをチューニングしました。これ以上早くしようと思ったら、HeapをチューニングしてGCの回数を減らすようにするしかありません。

5.1. まずは、「-Xmx1024m」を設定してヒープの上限を見極めましょう。
まずは、とても大きいHeapサイズを設定して、最大Heap値を見極めましょう。
本データですと、Peakは約40MBとなっている事が分かります。





5.2. 次に、ヒープのextensionを抑制してみましょう。
先程のデータで、約40MBは必要ということが分かったので、今度は最小Heapを60MBに設定してみましょう。
すると、以下の結果が得られました。どうもまだextensionされているようです。
因みに、GC回数が減っている事は注目です。これがextensionを抑制した時の効果です。





5.3. 「-Xmn32m」を試してみましょう。
Xmnとは、HeapのNew領域と呼ばれる部分のサイズの事です。JVMのデフォルト設定では、NEW領域の起動時のサイズが2MB、最大サイズが16MBとなっています。この値も、Heapのチューニングには大事な要素となります。
因みに、Xmnの値は最大Heap値の半分までにしましょう。
本オプションを付けて実行した結果、以下のデータが得られました。
GC回数が約1/5に減っていることが分かります。代わりに、GC一回当たりの平均時間が3倍に増えています。
これは、New領域を広げたことにより、GC一回当たりにスキャンするメモリ量が増えた事に起因していますが、全体としては実行時間短縮に効果があった事が分かります。
因みに、このパラメータを付けたらPeakのHeapが約84MBと増えてしまいました。





5.4. 「-Xms128m -Xmn64m」を試してみましょう。
上記の結果を受けて、最小Heap値とNew領域Heap値を上げました。
以下の結果を見ますと、まず、New領域を増やした所、GC回数が約半分、平均GC時間が約1.7倍位となっており、合計ではギリギリプラスとなっています。New領域のチューニングはこの辺りが限界でしょう。
また、最小Heap値を変更したことにより、めでたく「Full GC」がなくなりました。また、無事extensionもされなくなりました。
チューニングとしてはこの辺りが限界となります。





5.5. 「-Xmx1024m –Xms256m –Xmn128m」を試してみましょう。
ちょっと欲をだして、全体的に数字を増やしてみました。New領域を増やした分だけ遅くなっています。
Heap値をとにかく上げれば良い、というのは間違いという事が分かりました。
# 増やせば早くなるというものではありません。





6. 最後に


チューニング前と最終チューニング後の値を比べて見ましょう。
前: 552.219[s] 後: 368.080[s]
約1.5倍の速度向上をすることが出来ました。これの凄い所は、プログラムを変更する事無く、実行速度を1.5倍にする事が出来た、という所です。
# 全ての場合において、約1.5倍早くする事が出来る、という意味ではありません。
プログラム改修で速くなる場合も多々ありますが、それは本チューニングをやる前に改修しておきましょう。というのも、インスタンスの振る舞い(Heapの使用方法)が変われば、再度、本チューニングをやり直す必要があるからです。
本チューニングは、あくまで最終段階で行うチューニングと考えたほうが良いのかもしれません。

コメント

このブログの人気の投稿

雁尾千恵(37)

ResultSet.next()の高速化

TomcatでSessionを使いたくない場合