概要
JVM オプションは Java アプリケーションの性能とメモリ管理を左右する重要な設定ですが、種類が多く、どこから手をつけてよいか迷いがちです。開発環境では気にならなくても、本番環境でヒープが足りなくなったり GC の停止時間が問題になったりして初めて調べることも多いでしょう。この記事では、ヒープサイズ(-Xms / -Xmx)、GC アルゴリズムの選択(G1GC / ZGC)、GC ログの出力設定、OOM 時のヒープダンプ取得といった、実務で最も使用頻度の高い JVM オプションに絞って整理します。ManagementFactory API を使って実行中の JVM から設定値を取得・確認する方法も合わせて示します。
使いどころ
本番デプロイ前に -Xmx / -Xms を適切に設定し、ヒープ不足による OOM を予防する
GC ログ(-Xlog:gc*)を有効にして、性能劣化時に Full GC の発生状況を事後分析する
OOM 発生時にヒープダンプを自動取得し、Eclipse MAT でリーク箇所を特定する
コード例
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryUsage;
public class JvmOptionsDemo {
public static void main(String[] args) {
var runtime = Runtime.getRuntime();
// ヒープメモリ情報
System.out.println("=== JVM メモリ情報 ===");
System.out.println("最大ヒープ (-Xmx) : "
+ (runtime.maxMemory() / (1024 * 1024)) + " MB");
System.out.println("現在のヒープ : "
+ (runtime.totalMemory() / (1024 * 1024)) + " MB");
System.out.println("空きヒープ : "
+ (runtime.freeMemory() / (1024 * 1024)) + " MB");
System.out.println("CPU コア数 : "
+ runtime.availableProcessors());
// ManagementFactory で詳細情報を取得
var memBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heap = memBean.getHeapMemoryUsage();
MemoryUsage nonHeap = memBean.getNonHeapMemoryUsage();
System.out.println("\n=== ヒープメモリ詳細 ===");
System.out.println("使用中 : " + (heap.getUsed() / (1024 * 1024)) + " MB");
System.out.println("コミット済み: " + (heap.getCommitted() / (1024 * 1024)) + " MB");
System.out.println("最大 : " + (heap.getMax() / (1024 * 1024)) + " MB");
System.out.println("\n=== 非ヒープメモリ ===");
System.out.println("使用中: " + (nonHeap.getUsed() / (1024 * 1024)) + " MB");
// GC 情報
System.out.println("\n=== GC 情報 ===");
for (GarbageCollectorMXBean gc
: ManagementFactory.getGarbageCollectorMXBeans()) {
System.out.println("GC 名 : " + gc.getName());
System.out.println(" 回数 : " + gc.getCollectionCount());
System.out.println(" 累計時間: " + gc.getCollectionTime() + " ms");
}
// よく使う JVM オプション一覧
var options = """
=== よく使う JVM オプション ===
-Xms256m : 初期ヒープサイズ
-Xmx1g : 最大ヒープサイズ
-XX:+UseG1GC : G1GC(Java 9+ デフォルト)
-XX:+UseZGC : ZGC(Java 15+ 低レイテンシ)
-Xlog:gc* : GC ログ出力(Java 9+)
-XX:+HeapDumpOnOutOfMemoryError : OOM 時ヒープダンプ
-XX:HeapDumpPath=/tmp/heap.hprof: ダンプ出力先
""";
System.out.println(options);
}
}Version Coverage
デフォルト GC は G1GC。GC ログは -Xlog:gc* に統一。var と import 文の整理で ManagementFactory 周りのコードが読みやすくなる。ZGC が本番利用可能。
// Java 17: import + var で簡潔に
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryUsage;
var runtime = Runtime.getRuntime();
var memBean = ManagementFactory.getMemoryMXBean();
MemoryUsage heapUsage = memBean.getHeapMemoryUsage();
System.out.println("使用中: " + (heapUsage.getUsed() / (1024 * 1024)) + " MB");
// GC ログ: -Xlog:gc*
// デフォルト GC: G1GCLibrary Comparison
注意点
-Xmx を物理メモリの上限近くまで設定すると、OS やほかのプロセスのメモリが不足してスワップが発生し、かえって性能が悪化する
-Xms と -Xmx を同じ値にするとヒープの拡張・縮小が起きないため GC の負荷が安定するが、メモリを常時専有するのでコンテナ環境では注意が必要
Java 8 の -XX:+PrintGCDetails は Java 9 以降で廃止され、-Xlog:gc* に置き換わった。バージョンを跨ぐ運用ではオプションの互換性を確認すること
ZGC は低レイテンシに優れるが、スループット重視の大量バッチ処理では G1GC のほうが適する場合がある。ワークロードに応じた選択が必要
FAQ
ヒープの拡張・縮小による GC 負荷を避けたい場合は同じ値が有効です。ただし、コンテナ環境ではメモリ上限との兼ね合いを考慮し、余裕を持たせた設定が安全です。
レスポンスタイムの安定性が求められる API サーバーには ZGC(Java 15+)が適しています。スループット重視のバッチ処理では G1GC のほうが総処理時間が短くなる場合があります。
GC ログの出力は非常に軽量で、本番環境でも常時有効にしておくのが一般的です。問題発生時に遡って分析できるため、有効にしない理由は基本的にありません。