Prior to Java 8u191, Java configuration in Docker containers was a bit tricky because JVM Ergonomics set some values (like CPU cores or Heap memory limit) based on Docker daemon configuration. This behaviour forced to set JVM limits explicitly (with -Xmx for example) or via command line options (like -XX:+UseCGroupMemoryLimitForHeap). Now, with Java 8u191 or Java 10, the JVM sets theses values based on Docker container's configuration instead of Docker daemon.
We'll compare these different behaviours running a demo application in Java 8u121 and Java 8u191. Unlike the former, the latter is a container aware Java version.
The application visualizes the number of CPU cores and the memory limit in the logs:
public static void main(String[] args) {
long memory = Runtime.getRuntime().maxMemory();
int cpuCores = Runtime.getRuntime().availableProcessors();
LOGGER.info("Max Java Memory (MB): {}", memory / (1_024 * 1_024));
LOGGER.info("Max Java CPU Cores: {}", cpuCores);
}
We'll see that the values are different depending on the Java version.
This demo only requires Docker installed in your computer.
Clone this repo:
git clone https://github.com/wearearima/docker-java-cpu-memory-limit.git
Move to the downloaded repo, cd docker-java-cpu-memory-limit
, and build same image with different Java versions:
- Java 8u121 image:
docker build -t eu.arima/docker-java-cpu-memory-limit:java8u121 -f Dockerfile_java8u121 .
- Java 8u191 image:
docker build -t eu.arima/docker-java-cpu-memory-limit:java8u191 -f Dockerfile_java8u191 .
We can check the new images invoking docker image ls
:
REPOSITORY TAG IMAGE ID CREATED SIZE
eu.arima/docker-java-cpu-memory-limit java8u121 7e26f907aed2 29 hours ago 92.2MB
eu.arima/docker-java-cpu-memory-limit java8u191 c4eabbac6bd6 29 hours ago 88.6MB
Before comparing how JVM ergonomics behaves in each version, let's find out how much memory and how many cpu cores are configured in Docker daemon. To do so execute:
docker info
This command returns all information about Docker daemon's configuration. For this demo we only pay attention to CPUs
and Total memory
parameters. In my case these are the values:
CPUs: 2
Total Memory: 5.818GiB
Therefore, I've got configured 2 CPU cores and almost 6GB memory for all my containers.
For demonstration purposes, containers' memory and cpu will be limited running theses commands:
- Java 8u121 container:
docker run --memory=1GB --cpus=1 eu.arima/docker-java-cpu-memory-limit:java8u121
- Java 8u191 container:
docker run --memory=1GB --cpus=1 eu.arima/docker-java-cpu-memory-limit:java8u191
Memory is limited to 1 GB with --memory=1GB
option and CPU to one core with --cpus=1
option.
The result is:
Feature | Java 8u121 | Java 8u191 |
---|---|---|
Max Java Memory (MB) | 1324 | 247 |
Max Java CPU Cores | 2 | 1 |
With Java 8u191 java ergonomics has calculated the memory and cpu limits based on the configuration of the container (1GB and 1 cpu). However, the container with Java 8u121 has calculated these features based on the Docker daemon configuration (5.818GiB and 2 cpus).
Useful links: