Java起動オプション標準化

# この記事について
長年、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オプション（例）
``` shell
> 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 | 初期のヒープサイズ<br />物理メモリの量からOSが利用するメモリ量を引いた値を設定　-Xmxと同じ値にする |
| -Xmx                                         | ヒープサイズ最大             |            8192M | 最大ヒープサイズ<br />物理メモリの量から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ディレクトリに格納<br />%p=プロセスID,%t=タイムスタンプでファイル名を付ける<br />　コンテナ環境で実行する場合は、"stdout" と記載することにより、標準出力を利用することができる |
| [修飾]           |              time,tags | time=gcログにタイムスタンプを出力<br />tags＝ログにタグを設定　これはコンテナ環境などで標準出力を利用する際に便利 |
| [世代数]         |                     10 | ファイルの世代数                                             |
| [ファイルサイズ] |                   100M | 1ファイルのサイズ                                            |

## 終わりに
この記事にある設定値だけであれば楽に理解できると思います。このほかに監視エージェントへの接続設定があるかもしれませんが、それ以外の難しい設定を、意味が分からず呪い（まじない）のように使うのだけは止めましょう。状況を悪化させるだけでなので、おとなしくアプリケーションの実装を見直すべきだと思います。（長い経験から）