JVM flags & tuning basics in Java
-Xms, -Xmx, -Xss, choosing a GC, container awareness.
Four knobs
**-Xms sets the initial heap, -Xmx the maximum heap, -Xss** the stack size of each thread, and -XX: flags tune features, like **-XX:+UseZGC** to pick a collector.
java -Xms2g -Xmx2g -Xss1m \
-XX:+UseZGC -jar app.jarContainer-aware defaults
Modern JVMs are container-aware: they read cgroup memory and CPU limits, not the host's. Without heap flags, the max heap defaults to 25% of the available memory (MaxRAMPercentage).
No flags in a container
A container has a 2 GB memory limit and the JVM gets no heap flags. Roughly what max heap does it choose?
About 512 MB2 GB, the whole containerA quarter of the host machine's RAM
Show the answer
About 512 MB: 25% of the container limit, because the JVM reads the container's limit, not the host's. Many services raise the percentage to 50–75%.
-Xmx is not the process limit
-Xmx limits only the heap. Metaspace, thread stacks, the code cache, direct buffers and GC structures all come on top. With -Xmx2g in a 2 GB container there's no headroom, and the container gets killed.
# container limit: 2 GB
java -Xmx2g -jar app.jar # no headroom!Sizing in a container
java -Xmx4g -jar app.jarWrong as soon as the container limit changes.
java -XX:MaxRAMPercentage=75 \
-jar app.jarScales automatically with whatever limit the container gets.
Why -Xms = -Xmx?
Many production services set -Xms equal to -Xmx. What does that buy them?
Think about it, then reveal the answer
The heap is sized once at startup: committed up front, so the JVM never grows or shrinks it under load, and any memory shortage shows up at startup, not at peak traffic.
Deep recursion in prod
A recursive parser throws StackOverflowError on deeply nested but valid input. **-Xss gives threads bigger stacks as a quick fix; an iterative algorithm is the durable one. And always measure before you tune**: most flags only matter once data shows a problem.
Key takeaways
- -Xmx limits only the heap, not total process memory
- -Xss sets the per-thread stack size
- Containers: prefer -XX:MaxRAMPercentage over fixed sizes
- Default max heap = 25% of available memory
java -XX:+PrintFlagsFinal -version prints every JVM flag with its final value: hundreds of them.
Practice questions
A container has a 2 GB memory limit and the JVM gets no heap flags. Roughly what max heap does it choose?
- 2 GB, all of the container
- About 512 MB, 25% of the container limit
- A quarter of the host machine's RAM
- Exactly 64 MB
Check your answer
About 512 MB, 25% of the container limit. Modern JVMs read the container limit and apply MaxRAMPercentage, which defaults to 25%. Many services raise it to 50-75%.
A recursive parser throws StackOverflowError on deeply nested but valid input. Which flag gives threads a bigger stack?
- -XX:MaxMetaspaceSize
- -Xss
- -Xmx
- -Xms
Check your answer
-Xss. -Xss sets the stack size for new threads. A cleaner long-term fix is often an iterative algorithm instead of deep recursion.