JVM guideJVM Flags: The Practical Tuning Guide
Every JVM behavior you can influence — heap size, collector choice, GC logging, JFR — is a command-line flag or a runtime-mutable flag. The painful part is that most tuning advice is folklore, so this guide focuses on the flags you will actually set, how to see what's in effect, and how to change them on a running process.
Modern Java (9+) also has Unified Logging (-Xlog) and, since JDK 11, flags you can flip live with jinfo and jcmd -XX external commands — but never confuse 'set a flag live' with 'tune correctly.' Measure before and after.
The flags you'll actually set
These cover 95% of production tuning. Get these right before touching exotic -XX flags.
java -Xms2g -Xmx2g \ # initial & max heap
-XX:+UseG1GC \ # collector (G1 default in LTS 11/17/21)
-XX:MaxMetaspaceSize=512m \ # bound metaspace
-Xlog:gc*:file=gc.log:time,level,tags \ # GC log (JDK 9+)
-jar app.jar
| Flag | What it does | Common value |
|---|
| -Xms / -Xmx | Initial / max heap (set equal to avoid resize) | equal, e.g. -Xms2g -Xmx2g |
| -XX:MaxMetaspaceSize | Cap the (formerly permanent-gen) metaspace | 256m-512m |
| -XX:+UseShenandoahGC / UseZGC | Low-pause collectors (JDK-specific availability) | per workload |
| -XX:MaxGCPauseMillis | G1 adaptive pause target (soft goal) | 200 |
| -XX:+PrintGCDetails / -Xlog:gc | GC logging | on for diagnosis |
See what a JVM actually started with
Write good flags in the run script and verify with the runtime — not memory.
# Effective flags of a live JVM
jcmd <pid> VM.flags
jinfo -flags <pid>
# Just the GC collector / max heap
jcmd <pid> VM.flags | grep -iE 'UseG1|MaxHeap|Metaspace'
Change flags on a running JVM
Some flags are manageable at runtime via jinfo -flag and jcmd; others require a restart. Always confirm the flag is manageable before relying on a live tweak.
# Toggle a boolean or set a string flag live
jinfo -flag +PrintGC <pid>
jcmd <pid> VM.set_flag MaxGCPauseMillis 150
Tuning workflow (not folklore)
Baseline first, then change one variable. GC logging + a profiler give you before/after numbers.
# 1) baseline with GC log
java -Xlog:gc*:file=gc-baseline.log:time,level,tags -jar app.jar
# 2) profile hot methods
# 3) change ONE flag, repeat, compare
Flags to be careful with
Avoid cargo-cult -XX flags like -XX:+UseConcMarkSweepGC (removed in JDK 14). Prefer the defaults unless you have a measured reason. -XX:+TieredCompilation, -XX:+UseZGC etc. all have trade-offs.
Last updated August 2026 · JVM Tools is independent and not affiliated with Oracle.