MaxRAMPercentage done right
Fixed -Xmx in a container means two sources of truth: the deployment's memory limit and
the flag, which must change in lockstep. -XX:MaxRAMPercentage collapses them into one —
the JVM reads the cgroup limit (UseContainerSupport, on by default since JDK 10) and
sizes the heap as a percentage of it. Resize the limit, and the heap follows. Used
carelessly, though, it fails in two opposite ways.
Failure one: the default
With no heap flags at all, the JVM uses MaxRAMPercentage=25. A pod with a 1 Gi limit
gets a 256 MiB heap — the other 768 MiB mostly sits idle. The default exists so a JVM
sharing a machine stays polite; a dedicated container is not that machine. If you set no
heap flag, you are running on this default right now.
Failure two: the universal percentage
The opposite mistake is copying a "use 75%" recommendation everywhere. The non-heap side of the JVM — metaspace, code cache, thread stacks, GC structures — is mostly fixed cost: it does not shrink because the limit shrank. Say those overheads take 300 MiB:
- At a 2 Gi limit, 75% heap (1536 MiB) + 300 MiB fits with room to spare.
- At a 512 Mi limit, 75% heap (384 MiB) + 300 MiB = 684 MiB — the kernel kills the pod.
The safe percentage is a function of the limit, not a constant. Small pods need small percentages; large pods can push higher.
Computing a percentage you can trust
Work backwards from the breakdown: estimate the fixed overheads, subtract them (plus headroom) from the limit, and what remains is the largest safe heap — expressed as a floored percentage of the limit. That is exactly what the calculator does in "I know my container limit" mode, emitting the pair:
-XX:InitialRAMPercentage=70.0 -XX:MaxRAMPercentage=70.0
Initial equals Max for the same reason -Xms should equal -Xmx: a footprint that is
predictable from the first request.
The fine print
-Xmxwins. If both are present,MaxRAMPercentageis silently ignored — a classic source of "the flag does nothing" confusion. The Flags Audit catches this.- Recompute when the limit changes substantially. The percentage encodes the fixed overheads at one specific limit; halving the limit invalidates it.
MinRAMPercentageis not what it looks like. It applies only on tiny-memory systems (under roughly 200 MiB) and does not set a minimum heap on normal pods — most deployments should not touch it.- Verify what the JVM decided:
java -XX:MaxRAMPercentage=70.0 -XX:+PrintFlagsFinal -version | grep MaxHeapSizeinside the container shows the resolved heap.