How to prevent Java from exceeding the container memory limit?
I am running a java program in the docker container with a memory limit of 4GB I have set the maximum heap to 3gb, but the Java program still exceeds the limit and is killed (oomkilled)
My question is: how can I configure java to respect the set container limit and throw OutOfMemoryException instead of trying to allocate beyond the limit and let the host kernel kick its ass?
Update: I am an experienced Java developer and have a fair understanding of JVM I know how to set the maximum heap, but I wonder if anyone knows how to set the total memory limit declared by the JVM process from the operating system
Solution
When the Java application is executed in the container, the JVM Ergonomics (responsible for dynamically allocating resources according to the functions of the host) does not know that it is running in the container. It calculates the number of resources to be used by the Java application based on the host executing the container In view of this, if it is not important to set limits for containers, the JVM will use the host's resources as the basis for calculation
Starting with JDK 8u131 and JDK 9, there is an experimental VM option that allows JVM ergonomics to read memory values from cggroups To enable it, you must pass the following flags to the JVM:
If these flags are enabled, the JVM will know that it is running in the container and will ergonomically make the JVM calculate the resources of the application according to the container constraints rather than the host's functions
Enable flag:
$java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -jar app.jar
You can use the env variable to dynamically pass JVM options to the container
Example:
The command to run your application is similar to:
$java ${JAVA_OPTIONS} -jar app.jar
The docker run command needs to pass the env variable, as shown below:
$docker run -e JAVA_OPTIONS="-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap" myJavaImage
I hope this can help!