なみひらブログ

学んだことを日々記録する。~ since 2012/06/24 ~

利用しそうなJava実行時のオプション

背景

以下の本を読んで、利用しそうな「Java実行時のオプション」をメモっときます。
Javaパフォーマンス

Javaパフォーマンス

JITコンパイラのオプション

オプション 内容
-client - クライアントコンパイルを適用する
- Java実行後すぐにJITコンパイルを実施する。
- 起動後すぐにJITコンパイルされるコードがあるため起動直後が"-server"指定時よりも動作が早くなる。
- 起動時間を短くしたいアプリの場合はこっちを選択する(例:NetBeansなどのデスクトップGUIアプリなど)。
-server - サーバコンパイルを適用する
- Java実行後コードの振る舞いを学習して最適なJITコンパイルを行う。
- コードの振る舞いを見てから最適化されるため、長い目でみればクライアントコンパイルより動作が早くなる。
- 基本的こっちを選択する(デフォルトもこっち)
-d64 64ビットのサーバコンパイルを適用する。
- 64ビットマシンならこのオプションを指定するのが有効だが、今のJREは-serverオプションでも64bitとしてJITコンパイルしてくれるため"d64"オプションを指定することはないはず。

上記のクライアントコンパイルとサーバコンパイルの良い所を合わせた以下のようなオプションがあるが、

オプション 内容
-XX:+TieredCompilation - 階層的コンパイルを適用する
- 起動直後にJITコンパイルを行い、その後Java実行後コードの振る舞いを学習して最適なコンパイルも行う。
- "-server"指定時のみに有効。"-clinet"でこのオプションを指定しても無視される。

Java8以降はデフォルトで有効(true)になっているため明示的に指定することはない。

実行例

java -server

java -server -XX:+TieredCompilation

メモリ関連のオプション

言葉の整理

  • ヒープ領域:JavVMが動的に確保するメモリの領域。オブジェクトを生成したときとかに使われる。
  • young領域:ヒープ内に存在する領域。オブジェクトはまず置かれる領域。
  • old領域:ヒープ内に存在する領域。長く存在するオブジェクトはGCによってyoung領域からold領域に移動させられる*1
  • メタスペース:ヒープ領域とは別のところにあるメモリの領域*2。クラス/メソッドのメタ情報が配置される
    • Java8から、その他staticな情報はヒープ領域のほうに格納されるようになった。

基本的な方針

  • 以下のオプションで初期/最大メモリ量を指定しても、JavaVMはGUの発生具合を考慮して自動的にメモリ領域を拡張/縮小するため(adapting sizingという)、特に指定する必要はない。
  • ただ適切な値が事前にわかっておりその値をオプションとして指定しておけば、GC時の拡張判断(割り当て変更)がなくなるためGCの実行効率が良くなる。メモリ領域の変更はガベージコレクション時に行われスレッドが停止するため、できるだけ避ける設定が望ましい。
  • 一般的には、フルGC後にメモリ全体の30%相当をヒープに割り当てるぐらいがいいらしい。

オブション

オプション 内容
-Xms ヒープの初期サイズを指定する。
- 物理メモリ量を超えないように指定する。
- 最大でも「物理メモリ量 - 1G」程度に留めておく。
- 64bitLinux版JVMのデフォルトは「512MBと物理メモリの1/64のうち少ないほう」
-Xmx ヒープの最大サイズを指定する。
- 物理メモリ量を超えないように指定する。
- 最大でも「物理メモリ量 - 1G」程度に留めておく。
- 64bitLinux版JVMのデフォルトは「32GBと物理メモリの1/4のうち少ないほう」
-XX:NewRatio young領域に対するold領域のサイズの比を指定する。- 64bitLinux版JVMのデフォルトは2。つまりyoung領域33%でold領域66%で確保される。
-XX:MetaspaceSize メタスペースの初期サイズを指定する。
- 64bitLinux版JVMのデフォルトは「20.75MB」
-XX:MaxMetaspaceSize メタスペースの最大サイズを指定する。
- 64bitLinux版JVMのデフォルトは「無制限」。
- メモリを使い尽くしたらOutOfMemoryErrorが発生する。
- メタスペースもGCの対象なので、領域の自動拡張や不要なメモリ破棄が行われる。OutOfMemoryErrorが発生する場合はクラス/データ見直し、物理メモリ増設を検討する。
-XX:SurvivorRatio ヒープ内のsurvivor領域に対するeden領域のサイズの比を指定する。
- 64bitLinux版JVMのデフォルトは8。eden領域:survivor領域=8:2
-XX:TargetSurvivorRatio surviver空間の中で、空き領域として保持しておきたいサイズ比を指定する。
- デフォルトは50%
- フルGC後にsurviver空間自身の空きが50%を下回っていた場合、JVMがメモリサイズの調整がしようとする。
-XX:+HeapDumpOnOutOfMemoryError OutOfMemoryが発生したときにヒープダンプを生成する。
- 基本的に指定しておく。

実行例

  • メモリを指定して実行する。young領域とold領域は同じサイズの例(NewRatio=1)。以下のように初期値と最大値に同じ値を指定した場合、自動メモリ調整は無効になってしまうため一般的には避けたほうがいい(メモリ見積もりに自信があるとき以外は。)。

java -Xmx2048M -Xms2048M -XX:NewRatio=1 -XX:MetaspaceSize=512M -XX:MaxMetaspaceSize=512M

GC関連のオプション

オプション 内容
-XX:MaxTenuringThreshold JVMがオブジェクトをsurver空間に保持しておく期間の最大値を、GCの回数として表現する。
- デフォルトは、スループット型とG1は15、CMSは6(6回のGCを生き残ったオブジェクトがold領域に移動する)。
- 厳密にはJVMのデフォルトの動きは、JVMが昇格回数を1~MaxTenuringThresholdの間で自動調整する。
-XX:+PrintGCDetails GCに関する詳細なログを記録する。
- 基本的に指定しておいたほうがいい。
-XX:+PrintGCDateStamps GCのログを日時付きで出力する。
- 基本的に指定しておいたほうがいい。
-XX:+PrintClassHistogram スレッドダンプ取得時にクラスの統計情報(個数と合計メモリ消費量)
- 基本的に指定しておいたほうがいい。

まとめ

  • 最近のJVMは設定を変更できるオプションがたくさんある。
  • 一方で最近のJVMは動作しながらいい感じで自分でチューニングしてくれるので、結局は設定はいじらないほうがいい(;´Д`)バージョン間の互換がない/廃止されるオプションもあるし。
  • なのでどちらかというと、解析時に利用できるダンプやログ周りに関するオプションに詳しくなっておいたほうがいい。
    • 本記事ではあまり書いていない(;´Д`)

参考

*1:young領域から直接old領域に移動することもあるが、厳密にはyoung領域内に存在するsurvivor領域に移動する(eden領域->survivor領域)という段階を踏むことが一般的。

*2:Java8から導入された概念。Java7以前のPermanent領域に相当する。