コンパイラフラグ
JVMチューニングで最初に検討するのがコンパイラの選択となる。
ただ、近年は階層的コンパイルが有効になっていたり、プラットフォーム別で適した設定がデフォルトで有効になっていることもあり、改めて設定するケースは少ない。
フラグ | 説明 |
---|---|
-client |
クライアントコンパイラ(C1)を使用する |
-server |
サーバコンパイラ(C2)を使用する |
-server -XX:+TieredCompilation |
階層的コンパイルを使用する |
コンパイラは、クライアントコンパイラ(C1)、サーバコンパイラ(C2)の2種類があり、JVM起動オプションで指定する。
C1コンパイラはデスクトップアプリケーションのように起動時の速度が重要な場合に、早期にJIT(just-in-time)コンパイルを開始する。
一方C2コンパイラはコードの振る舞いを十分に解析した後にコンパイルを開始する。これによりより効果的な最適化が実現できる。
大雑把に言うと以下となる
- C1:コンパイルが早く生成されるコードが遅い
- インタプリタ 実行しながらHotなメソッドを検出
- ネイティブ Hotと判定したメソッドをJITコンパイルして実行する
- C2:コンパイルが遅いが生成されるコードが早い
- インタプリタ 実行しながらプロファイリングする
- ネイティブ Hotと判定したメソッドをプロファイリングデータを使ってJITコンパイルして実行する
C2はプロファイリングデータを必要とするためインタプリタのフェーズが長く、アプリケーションの起動直後はパフォーマンスが出ない。
これを解消するために -XX:+TieredCompilation
オプションがあり、起動早期からコンパイルを行い、サーバコンパイラによりホットな部分を改めて(より最適化された)コンパイルを行うことができる。これはJava7u4以降で実用に達し、Java8ではデフォルトで有効化されている。
Java8 では階層的コンパイルを選択すれば良いが、コードキャッシュ(-XX:ReservedCodeCacheSize=N
にて指定)が多く必要となるので注意が必要。
コードキャッシュのサイズが不足した場合、(コードキャッシュが空くまで)JITコンパイルが停止し、インタプリタモードで動作するため、パフォーマンス劣化の原因となる場合がある。これについては後述する。
GC戦略
GC戦略はアプリケーションの要件と照らして適切なものを選択する必要がある。
フラグ | 説明 |
---|---|
-XX:+UseSerialGC |
シリアル型GC。マイナーGC、フルGCの両方がアプリケーションを停止して処理される |
-XX:+UseParallelGC -XX:+UseParallelOldGC |
パラレル型GC。young領域とold領域のGCに複数スレッドが利用される。マイナーGC、フルGCの両方でアプリケーションスレッドは停止 |
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC |
CMS型GC。マイナーGCではアプリケーションスレッドを停止し、複数スレッドで処理。old領域はアプリケーションスレッドと並行でGCが行われる |
-XX:+UseG1GC |
CMS型GCを複数のリージョンに分割したヒープ上で行う。CMS型GCに比べてold領域の断片化が発生しにくい |
シリアルGC
- 最もシンプルなGC
- 単一CPUの32bitプラットフォームのデフォルト
- GC処理は常にアプリケーションスレッドが停止
- 小さなヒープ(100M程度)の場合の選択肢
パラレルGC
- GC処理は常にアプリケーションスレッドが停止
- マイナーGCを複数スレッドで処理
-XX:+UseParallelOldGC
フラグによりフルGCも複数スレッドで処理- GCによる長いストップ・ザ・ワールドが許容でき、スループットを最大化する場合の選択肢
CMSGC
- マイナーGC時にはアプリケーションスレッドが停止
- マイナーGCは複数スレッドで処理(
-XX:+UseParNewGC
のアルゴリズム利用) - old領域のGC時にはアプリケーションスレッドが停止しない
- バックグラウンドスレッドにより並列で未使用オブジェクトを破棄
- old領域が断片化が進行した場合、アプリケーションスレッドを停止してクリーンアップとコンパクト化を単一スレッドで実施
- 同種の
-XX:+CMSIncrementalMode
(細かい単位でGCを行う) は今では推奨されていない
G1GC
- マイナーGC時にはアプリケーションスレッドが停止
- マイナーGCは複数スレッドで処理
- old領域のGC時にはアプリケーションスレッドが停止しない
- バックグラウンドスレッドにより並列で未使用オブジェクトを破棄
- ヒープはリージョンに分割されており、断片化が発生しにくい
- 大きなヒープ(4G以上)でアプリケーションの停止を望まず、CPUに余裕のある場合の選択肢
GCログ
GCログは商用利用であれば必ず設定しておきたい。
フラグ | 説明 |
---|---|
-verbose:gc |
GCログを出力 |
-Xloggc:<パス> |
GCログをファイル出力 Java8からは gc_%p_%t.log のようにすると、%pにPID, %tに日時が入ったファイルが作成できる |
-XX:+PrintGCDetails |
GCの詳細出力 |
-XX:+PrintGCDateStamps |
GCログに日時出力する。-XX:+PrintGCTimeStamps だと相対時間となり見にくい |
-XX:+PrintGCApplicationStoppedTime |
Stop The World した時間を出力 |
-XX:+UseGCLogFileRotaiton |
GCログのログローテートを有効化 |
-XX:+NumberOfGCLogFiles=N |
GCログの世代保持数 |
-XX:+GCLogFileSize=N |
GCログのログローテートの閾値 10M のように指定 |
ヒープ関連
フラグ | 説明 |
---|---|
-XX:+PrintClassHistogram |
スレッドダンプ取得時にヒープ統計情報を出力 |
-XX:+HeapDumpOnOutOfMemoryError |
OutOfMemoryError発生時にヒープダンプを出力 |
設定しておきたい Java 起動オプション
フラグ | 説明 |
---|---|
-server |
C2を有効化 |
-Xms |
初期ヒープサイズ。 -Xmx と同値にしたい |
-Xmx |
最大ヒープサイズ |
-Xmn (-XX:NewSize -XX:MaxNewSize ) |
New領域サイズ |
-XX:PermSize |
Perm領域初期サイズ。-XX:MaxPermSize と同値にしたい(~Java7) |
-XX:MaxPermSize |
Perm領域最大サイズ(~Java7) |
-XX:MetaspaceSize |
メタスペースのGCを実施する目安サイズ指定(Java8~) |
-XX:MaxMetaspaceSize |
メタスペースの最大サイズを指定する(Java8~) |
-XX:ReservedCodeCacheSize |
コードキャッシュサイズ |
-Xloggc:<パス> |
GCログをファイル出力 |
-XX:+PrintGCDetails |
GCの詳細出力 |
-XX:+PrintGCTimeStamps |
GCログにタイムスタンプ出力 |
-XX:+PrintGCDateStamps |
GCログに日時出力 |
-XX:+PrintGCApplicationStoppedTime |
Stop The World した時間を出力 |
-XX:+UseGCLogFileRotaiton |
GCログのログローテートを有効化 |
-XX:+NumberOfGCLogFiles=N |
GCログの世代保持数 |
-XX:+GCLogFileSize=N |
GCログのログローテートの閾値 |
-XX:+PrintClassHistogram |
ヒープ統計出力用 |
-XX:+HeapDumpOnOutOfMemoryError |
OutOfMemoryError時にヒープダンプ出力 |
MaxMetaspaceSize
のデフォルトは超でかいので、メモリリークの予防の意味で設定しておきたい-XX:ReservedCodeCacheSize
近年動的なクラス生成などで必要量が多くなる傾向があり、コードキャッシュが足りなくなるとJITコンパイラが停止して突然のパフォーマンス劣化になるので注意して設定-XX:+PrintCodeCache
(VM終了時にコードキャッシュ情報を出力) や-XX:+PrintCodeCacheOnCompilation
(JITコンパイル時にコードキャッシュ情報を出力)なども使い見極めた上で設定したい-XX:+PrintCodeCache
(VM終了時にコードキャッシュ情報を出力) や-XX:+PrintCodeCacheOnCompilation
(JITコンパイ
- GC戦略は、CMSGC か、超潤沢なメモリを使える場合はG1GCが選択子になり、CMSGC の場合は例えば以下ぐらいでまずはいいと思う(だいたいデフォルトで有効だけど)
-XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+CMSClassUnloadingEnabled
-XX:SurvivorRatio
や-XX:MaxTenuringThreshold
や-XX:TargetSurvivorRatio
などはチューニング候補になるが、最近の Java であればプラットフォーム別のデフォルト値のままでも下手にチューニングするより良いと思う。- 昔のデフォルト '-XX:MaxTenuringThreshold=32' は Java8 では 0~15 でないと起動できないなどあるしネ
-XX:+CMSClassUnloadingEnabled
はクラスアンロードを有効にするのでPermを十分にとった上で有効にするのもいいと思う-XX:+UseCMSInitiatingOccupancyOnly
と-XX:CMSInitiatingOccupancyFraction=N
は状況に応じてだけど、いらないかな
まとめ
今は下手にチューニングするならデフォルトの方が良いと思います。
- 作者:Scott Oaks
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/04/11
- メディア: 大型本
- 作者:ジャック シラジ
- 出版社/メーカー: オライリージャパン
- 発売日: 2003/10
- メディア: 単行本