この記事について
長年、Javaを使ったIT開発の仕事をしていますが、Javaの起動オプション決定は毎回試行錯誤している気がします。
GCの特性毎にHeap,Metaspace,New領域(Eden/Survivor),Old領域などの複雑なメモリ管理を調べつつ、-Xオプションを設定してみる
この作業、10年前から変わってない気がします。
細かいJavaのメモリ管理については別の記事に譲るとして、ここでは完結に
ここだけいじればオーケー
的な情報を示したいと思います。
ご意見などあれば、是非コメントお願いします。
前提
ここでは、常駐して利用されるJavaVM(OpenJDK 8u20以降のHotspot JavaVM)の起動オプションを想定しています。
常駐とは・・・
- アプリケーションを起動したら、停止命令を送るまで起動したままの物
- 代表例はTomcatやJetty,WildFlyなどのアプリケーションサーバ
- Spring-bootを使ったアプリケーション
- もちろん自作のJavaSEアプリケーションでも常駐するものならOK
対象外を言えばよかったかも
- 一回実行して、処理が終了したらJavaVMも終了するものは対象外
商用環境JavaVM 推奨起動オプション
ここでは起動オプション(例)を先に示し、それぞれの項目の意味と設定内容を説明します。
この設定をベースにヒープサイズやファイル出力先ぐらいを変更(チューニング?)すればよいでしょう。
起動オプション決定方針
JavaVM起動オプション様々な設定が存在しますが、可能な限りエルゴノミクス・デフォルト(※)を利用し、最低限の設定を行うものとします。
※ エルゴノミクス・デフォルト:JavaVMが利用環境(CPUコア数やOS、物理メモリ量などの情報)から最適な値を自動設定します。要するに、できる限りJavaVMにおまかせすると言うことです。
JavaVMオプション(例)
> java -Xms8192M
-Xmx8192M
-XX:+CrashOnOutOfMemoryError
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/AAA/BBB/CCC/hprof-dumps
-Xlog:gc:file=/AAA/BBB/CCC/gclogs/gc_%p_%t.log:time:filecount=10:size=100M
(以降、メインクラス名 アプリケーション固有の起動引数)
起動オプションの内容
- GCアルゴリズム=G1GCを使用(デフォルト)
- 最大停止時間目標 200ms(デフォルト)
- metaspace,SurvivorRatio/NewRatioなどは、JavaVMにおまかせ
- ヒープサイズ8192Mバイト 最大=最小
- OutOfMemoryErrorが発生した時はプロセスを停止し、クラッシュレポートを出力
- OutOfMemoryErrorが発生した時に、ヒープダンプを出力
- ヒープダンプの出力先:/AAA/BBB/CCC/hprof-dumps
- gcログ関連
- gcログファイルは /AAA/BBB/CCC/gclogs/に格納する
- ファイル名はgc_[プロセスID]_[時間].log
- 1ファイルのサイズ=100Mバイト
- ファイル世代数=10 でローテーション
- gcログに各行にタイムスタンプを出力する
JavaVMオプションまとめ
よく使うJavaVM起動オプションの説明と、設定値の決め方を以下にまとめます。
起動オプション(-Xlog:gc以外)
起動オプション | 設定値 | 設定値の例 | 説明(決め方) |
---|---|---|---|
-Xms | ヒープサイズ最小 | 8192M | 初期のヒープサイズ 物理メモリの量からOSが利用するメモリ量を引いた値を設定 -Xmxと同じ値にする |
-Xmx | ヒープサイズ最大 | 8192M | 最大ヒープサイズ 物理メモリの量からOSが利用するメモリ量を引いた値を設定 -Xmsと同じ値にする |
-XX:MaxGCPauseMillis | 停止してもよい時間(ミリ秒) | 200 | GCによる最大停止時間の目標。省略時は200ms。GCが頻発する場合は増やしてみる。 |
-XX:+CrashOnOutOfMemoryError | - | - | OutOfMemory発生時にプロセスを終了し、クラッシュレポートを出力する。これはいつも設定すべき |
-XX:+HeapDumpOnOutOfMemoryError | - | - | OutOfMemory発生時にヒープダンプを出力する。ヒープが大きい場合は、ヒープダンプファイルも大きくなるため、出力先に注意する。見るつもりがないなら出力しない |
-XX:HeapDumpPath= | ヒープダンプの出力先 | /.../hprof-dumps | 上記ヒープダンプの出力先 |
-Dcom.sun.management.jmxremote= | JMXリモート接続の許可 | true | 監視ツールなどからJMXリモート接続する場合に設定 |
-Dcom.sun.management.jmxremote.port= | 上記接続ポート | 7091 | 上記接続時のポート番号 |
-Dcom.sun.management.jmxremote.authenticate= | 上記接続時に認証するか | false | 上記接続時に認証するか |
-Dcom.sun.management.jmxremote.ssl= | 上記接続時にSSL通信するか | false | 上記接続時にSSL通信するか |
起動オプション(-Xlog:gc)詳細にgcログを出力したい場合は -Xlog:gc*
-Xlog:gc:[ファイル名]:[修飾]:filecount=[世代数]:size=[ファイルサイズ]
設定項目 | 設定例 | 説明(決め方) |
---|---|---|
[ファイル名] | /gclogs/gc_%p_%t.log | /gclogsディレクトリに格納 %p=プロセスID,%t=タイムスタンプでファイル名を付ける コンテナ環境で実行する場合は、"stdout" と記載することにより、標準出力を利用することができる |
[修飾] | time,tags | time=gcログにタイムスタンプを出力 tags=ログにタグを設定 これはコンテナ環境などで標準出力を利用する際に便利 |
[世代数] | 10 | ファイルの世代数 |
[ファイルサイズ] | 100M | 1ファイルのサイズ |
終わりに
この記事にある設定値だけであれば楽に理解できると思います。このほかに監視エージェントへの接続設定があるかもしれませんが、それ以外の難しい設定を、意味が分からず呪い(まじない)のように使うのだけは止めましょう。状況を悪化させるだけでなので、おとなしくアプリケーションの実装を見直すべきだと思います。(長い経験から)