Tomcatのメモリチューニング+α
はじめに
Tomcatをサーバ上で運用するときのメモリ割り当てなどの設定に困ったので色々調査してまとめてみました。
TL;DL
以下が今回作成した設定値。
【2018/04/11時点】 -d64 -server -XX:+UseCompressedOops -Xms1024m -Xmx1024m -XX:NewSize=384m -XX:MaxNewSize=384m -XX:MaxMetaspaceSize=256m -XX:CompressedClassSpaceSize=256m -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseParNewGC -XX:SurvivorRatio=6 -XX:MaxTenuringThreshold=15 -XX:TargetSurvivorRatio=80 -Xloggc:/${CATALINA_BASE}/logs/gc.`date '+%Y-%m-%d'`.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintClassHistogram -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/${CATALINA_BASE}/logs/java.hprof
メモリ空間の使い方
Tomcatを起動すると、以下のようにメモリ空間を確保します。
領域 | 説明 |
---|---|
サーバ上のメモリ空間 | 名前の通り。サーバ上の物理メモリの領域。 |
Javaヒープ | Tomcat上で動作するJavaプログラムのリソースを管理する領域。New領域とOld領域で構成される。 |
New領域 | 新規オブジェクトと閾値未満のオブジェクトが格納される。 |
Eden | 新規のオブジェクトが格納される。 |
From | CopyGC(ScavengeGC、マイナーGC)が実行されたとき、使用中のオブジェクトはここへコピーされる。Survivorとも呼ばれる。 |
To | CopyGC(ScavengeGC、マイナーGC)が実行されたとき、使用中のオブジェクトはここへコピーされる。Survivorとも呼ばれる。 |
Old(領域) | GCで閾値を超えたオブジェクトが格納される。 |
Nativeメモリ | Javaヒープ領域がJVMによって管理される領域に対して、NativeメモリはOSによって管理されるメモリ領域のこと。 |
Metaspace | クラスやメソッドの情報が格納される領域。 |
Cヒープ | Javaスレッドなどのバッファ領域として使用される。 |
スレッドスタック | スレッド毎に保持するスタック領域。命令の順序をスタックする。 |
※FromとToの違いはGCを参照。
GC(ガベージコレクション)について
GCとは、プログラムが確保したメモリ領域のうち、不要になった領域を自動的に解放する機能です。 使用できるメモリ領域が少なくなるとCopyGCまたはFullGCのどちらかが実行されます。 CopyGCはEden領域がいっぱいになると発生します。つまりCopy領域の対象はNew領域です。 一方、FullGCは対象がJavaヒープの全領域です。Old領域がいっぱいになると発生します。 CopyGCとFullGCの大きな違いは、GC処理の時間です。CopyGCの場合対象が狭いため、GCが必要になったとしてもGCにかかる時間が少なく、WEBアプリケーションに与える影響が少ないというメリットがあります。
GC | 対象領域 | 所要時間 | アプリケーションへの影響 | 説明 |
---|---|---|---|---|
CopyGC | New領域 | 短い | 小さい | 影響が小さいためある程度なら起こっても問題ない(頻発するのはNG) |
FullGC | Javaヒープ領域 | 長い | 大きい | 処理時間が長いためGC発生は最小限にとどめたい |
メモリ割当やその他諸々のオプション設定
上記構造よりメモリ割当を考えていきます。 Javaヒープのメモリ領域は多ければ多いほどいいと考えられますが、無限のメモリを搭載することはできないのでGCが起こることは避けられません。 また、搭載メモリの中で可能な限り大きく領域を確保してしまうと、CopyGCが発生してしまった場合に、処理すべきメモリ量が多くなってしまい、本来の処理時間よりも多くの時間がかかってしまう懸念があります。 よって、中途半端に大きくとるよりも、少量でも適切なメモリ量を設定した方が、システム全体のレスポンスが良くなると考えられます。
上記と詳細仕様(内容は伏せます)より、今回は以下の設定を作成しました。
【2018/04/11時点】 -d64 -server -XX:+UseCompressedOops -Xms1024m -Xmx1024m -XX:NewSize=384m -XX:MaxNewSize=384m -XX:MaxMetaspaceSize=256m -XX:CompressedClassSpaceSize=256m -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=70 -XX:+UseParNewGC -XX:SurvivorRatio=6 -XX:MaxTenuringThreshold=15 -XX:TargetSurvivorRatio=80 -Xloggc:/${CATALINA_BASE}/logs/gc.`date '+%Y-%m-%d'`.log -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintClassHistogram -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/${CATALINA_BASE}/logs/java.hprof
※64bitとして動作することや、サーバータイプで動作すること、ログの出力などの設定を追加しています。