HotSpot Ergonomics and Docker

When no maximum heap size is specified using -Xmx the Java HotSpot Virtual Machine uses ergonomics to set the maximum heap size. In partice this means one quarter of the physical memory. On Java 8 per default cgroups memory limits are ignored. We can observe this using

docker run -it --rm -m 8g openjdk:8 java -XX:+UseParallelGC -XX:+PrintFlagsFinal -version | grep MaxHeapSize
    uintx MaxHeapSize                              := 16873684992                         {product}

On a machine with 64 gigabyte of memory we get a maximum 16 gigabyte heap even though we set the memory limit to 8 gigabytes. Later versions of Java 8 can be made to respect cgroup limits

docker run -it --rm -m 8g openjdk:8 java -XX:+UseParallelGC -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -XX:+PrintFlagsFinal -version | grep MaxHeapSize
    uintx MaxHeapSize                              := 2147483648                          {product}

Now the cgroup limit of 8 gigabytes as regarded as the amount of available memory and per default we get a maximum heap of one quarter of this with results in a maximum 2 gigabyte heap. Java 10 does this by default

docker run -it --rm -m 8g openjdk:10 java -XX:+UseParallelGC -XX:+PrintFlagsFinal -version | grep MaxHeapSize
   size_t MaxHeapSize                              = 2147483648                               {product} {ergonomic}

Java 10 allows for easy control of what percentage of memory should be used for the heap using MaxRAMPercentage

docker run -it --rm -m 8g openjdk:10 java -XX:+UseParallelGC -XX:MaxRAMPercentage=75 -XX:+PrintFlagsFinal -version | grep MaxHeapSize
   size_t MaxHeapSize                              = 6442450944                               {product} {ergonomic}

and we end up with a 6 gigabyte heap, 75% of 8 gigabytes.

Having that said I would still recommend sizing the heap using -Xmx based on the live set and sizing the docker container based on the memory requirements of the JVM rather than the other way around.