Definition
JVM flags configure the runtime at launch. -Xms sets the initial heap size and -Xmx sets the maximum heap size; setting them equal avoids runtime resizing. -XX:+UseG1GC selects the garbage collector. -XX:MaxGCPauseMillis sets G1's soft pause-time target. -XX:MetaspaceSize sets the threshold at which the first Metaspace garbage collection is triggered, and -XX:MaxMetaspaceSize caps how large Metaspace can grow. Together these control memory sizing, collection behavior, and class-metadata limits.
Understanding the Concepts
Heap sizing: -Xms and -Xmx
-Xms sets the heap size the JVM starts with, and -Xmx sets the absolute maximum it may grow to. If the application needs more than the current heap and it is below -Xmx, the JVM grows the heap, which involves work and can cause GC activity. In production, set -Xms equal to -Xmx so the heap is allocated once at startup and never resized, giving predictable behavior and avoiding resize pauses.
# Production: pin heap size to avoid runtime resizing
java -Xms4g -Xmx4g -jar bank-api.jar
# Development: allow growth from small initial size
java -Xms512m -Xmx2g -jar bank-api.jar
Sizing -Xmx too small causes frequent GC and OutOfMemoryError. Sizing it too large wastes memory and can lengthen pauses because the collector has more ground to cover.
Garbage collector selection
-XX:+UseG1GC explicitly selects the G1 collector. There are matching flags for other collectors.
java -XX:+UseSerialGC # Single-thread, small heaps
java -XX:+UseParallelGC # Throughput-first, batch jobs
java -XX:+UseG1GC # Balanced (Java 9+ default)
java -XX:+UseZGC # Ultra-low latency
java -XX:+UseShenandoahGC # Low latency (alternative to ZGC)
Selecting the collector explicitly is good practice even when it is the default, because it documents intent and protects you if the default changes across JVM versions.
Pause-time target: -XX:MaxGCPauseMillis
-XX:MaxGCPauseMillis gives G1 a soft target for the maximum stop-the-world pause, defaulting to 200 ms. G1 uses it to decide how much to collect per pause: a smaller value makes G1 collect fewer regions each time so pauses are shorter, but it collects more often, which can reduce throughput. It is a goal, not a guarantee.
# Target 100ms pauses for a customer-facing API
java -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -Xms4g -Xmx4g -jar bank-api.jar
Metaspace sizing
-XX:MetaspaceSize sets the initial high-water mark at which the first Metaspace GC runs; after that the JVM adjusts the threshold. -XX:MaxMetaspaceSize caps Metaspace so a class-loading leak cannot consume unlimited native memory and take down the host.
# Cap Metaspace to prevent class-loader leaks from killing the host
java -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -jar bank-api.jar
Without a cap, a leak (for example repeatedly loading classes via dynamic proxies) grows Metaspace until the machine runs out of native memory.
Diagnostic flags (non-negotiable in production)
Two more flags belong in every production setup even though they are not sizing flags.
java -XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/var/dumps/ \
-Xlog:gc*:file=/var/log/gc.log:time,level,tags \
-Xms4g -Xmx4g -XX:+UseG1GC \
-jar bank-api.jar
| Flag | Purpose |
|---|---|
| -XX:+HeapDumpOnOutOfMemoryError | Auto-capture heap dump on OOM |
| -XX:HeapDumpPath | Where to write the dump file |
| -Xlog:gc* (Java 9+) | Enable GC logging for observability |
| -XX:NativeMemoryTracking=summary | Track native memory usage by category |
Complete production example
Here is a complete JVM configuration for a banking transfer service at National Bank of India.
java \
-Xms4g -Xmx4g \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=150 \
-XX:MetaspaceSize=128m \
-XX:MaxMetaspaceSize=256m \
-XX:+HeapDumpOnOutOfMemoryError \
-XX:HeapDumpPath=/var/dumps/transfer-service.hprof \
-Xlog:gc*:file=/var/log/gc-transfer.log:time,level,tags \
-jar transfer-service.jar
Every flag here maps to a real production concern: pinned heap avoids resize jitter, G1 with a pause target keeps transfers responsive, Metaspace cap catches class-loading leaks, and the diagnostic flags ensure you can diagnose any OOM after the fact. Flags should be chosen from measurement and load testing, not copied blindly from the internet.
Key Takeaway
The essential JVM flags fall into three groups: sizing the heap, choosing and tuning the garbage collector, and bounding class metadata. For the heap, -Xms sets the initial size and -Xmx sets the maximum, and in production I almost always set them equal, like -Xms4g -Xmx4g, so the heap is allocated once at startup and never resized during traffic, which removes a whole class of latency jitter. For the collector, -XX:+UseG1GC explicitly selects G1, and I set it explicitly even when it is the default so my intent is documented and safe across JVM versions. -XX:MaxGCPauseMillis gives G1 a soft target for the longest pause, and I remember it is a goal, not a guarantee, and that setting it too low just makes G1 collect more often and hurt throughput. For class metadata, -XX:MetaspaceSize sets the threshold for the first Metaspace collection and -XX:MaxMetaspaceSize caps it so a class-loading leak cannot eat unlimited native memory and crash the host.
The two flags I consider non-negotiable in production even though they are not sizing flags are -XX:+HeapDumpOnOutOfMemoryError with a -XX:HeapDumpPath, so that when an OutOfMemoryError ever happens I automatically get a heap dump to analyze instead of losing the evidence, and -Xlog:gc so that GC behavior is observable from day one. And I always stress that flags should come from measurement and load testing, never from copying a config off the internet.
In my banking work at National Bank of India, I tuned our transfer service exactly this way. We had been seeing response-time jitter that turned out to be the heap resizing under load, so I pinned -Xms equal to -Xmx. We selected G1 with a modest pause target so transfers never appeared to hang. And after a proxy-generating library slowly leaked class metadata, I capped -XX:MaxMetaspaceSize so the leak would fail fast and visibly with a clear OutOfMemoryError in Metaspace, triggering an alert, rather than silently consuming native memory until the whole host fell over. Every one of those flags maps to a real production incident I have had to reason about.
Remember one sentence: What are the essential JVM flags: -Xms (initial heap), -Xmx (max heap), -XX:+UseG1GC (choose GC), -XX:MaxGCPauseMillis (target pause), -XX:MetaspaceSize / -XX:MaxMetaspaceSize (class metadata limit) is fundamental knowledge for Java interviews and production banking work.
---