When a Java application is executed inside a container, the JVM ergonomics (which is responsible for dynamically assign resources based on the host's capabilities) does not know it is running inside a container and it calculates the number of resources to be used by the Java app based on the host that is executing your container. Given that, it does not matter if you set limits to your container, the JVM will take your host's resources as the base for doing that calculation.
From JDK 8u131+ and JDK 9, there’s an experimental VM option that allows the JVM ergonomics to read the memory values from CGgroups. To enable it you must pass the following flags to the JVM:
-XX:+UnlockExperimentalVMOptions and -XX:+UseCGroupMemoryLimitForHeap
If you enable these flags, the JVM will be aware that is running inside a container and will make the JVM ergonomics to calculate the app's resources based on the container limits and not the host's capabilities.
Enabling the flags:
$ java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -jar app.jar
You can dynamically pass the JVM options to your container with ENV variables.
Example:
The command to run your app would like something like:
$ java ${JAVA_OPTIONS} -jar app.jar
And the docker run command needs to pass the ENV variable like this:
$ docker run -e JAVA_OPTIONS="-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap" myJavaImage
Hope this helps!
Error
and it is unlikely that you are able to get back on your feet after aOOME
. To prevent the JVM to use too much memory, you need to reduce the consumption of memory in your application or you need to upgrade your container with more memory allocated. – Bradberryjava
console command. Updates in the comments are not as noticeable for future readers. Thanks! – Cowskin