JVM settings inside a container

Docker · lesson 14 of 31 · 4 min read

Size the heap against the container limit so the kernel stops killing your Java process.

Open this lesson in the learning hub

Key points

  • Since Java 10 the JVM reads cgroup limits, not the host specs. UseContainerSupport is on by default.
  • Default max heap is only 25% of the container memory limit. On a 1 GB container that is about 256 MB.
  • Prefer -XX:MaxRAMPercentage=75 over a hard-coded -Xmx. It follows the limit when you resize the container.
  • Heap is not the whole footprint. Metaspace, thread stacks, code cache and direct buffers live outside it, so leave headroom.
  • Exit code 137 means the kernel OOM-killed the process. Raise --memory or lower the percentage.
  • CPU limits shrink availableProcessors() and therefore your GC and ForkJoin pools. Under 2 CPUs the JVM falls back to SerialGC.

Example

# always set a limit, then size the heap against that limit
docker run -d --memory=1g --cpus=2 -p 8080:8080 \
  -e JAVA_TOOL_OPTIONS="-XX:MaxRAMPercentage=75 -XX:+UseG1GC" \
  myapp:1.0

# what does the JVM believe it has?
docker run --rm --memory=1g eclipse-temurin:21-jre \
  java -XX:+PrintFlagsFinal -version | grep -E "MaxHeapSize|MaxRAMPercentage|ActiveProcessorCount"

# it died. why?
docker inspect --format '{{ .State.ExitCode }} {{ .State.OOMKilled }}' myapp

Set --memory, then set MaxRAMPercentage. Never let the JVM guess.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the Docker course, and every lesson in it is listed on the Docker contents page.