gaku(SE)の私的な気まぐれアウトプット

技術メモやガジェット、時々趣味についてアウトプットするブログ

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を起動すると、以下のようにメモリ空間を確保します。

f:id:gaku358:20181019102738p:plain

領域 説明
サーバ上のメモリ空間 名前の通り。サーバ上の物理メモリの領域。
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として動作することや、サーバータイプで動作すること、ログの出力などの設定を追加しています。