Docker for Java Developers - How the JVM runtime works in a container

As container deployments become increasingly common, it is important to understand how your application and runtime cooperate with various Linux container technologies.

Depending on your JVM target version, you may need to do a little extra work to ensure your java runtime is aware of the processor and memory usage limits. If you are not careful, your application may have incorrect optimization or heuristics applied, potentially leading to performance issues and even crashes.

Namespaces and Cgroups

First, if you need to brush up on the underlying Linux technologies that make Docker possible, you might want to read Julia Evans excellent blog post here.

With a basic understanding of cgroups and namespaces we can now turn our attention to ensuring our Java runtime is aware of these technologies. Here is what you need to know in order to ensure your Java runtime is aware of the memory and processor limits set on your containers.

Java 7

Sadly there are no flags or features available in JDK 7 to provide container awareness. If you are running on JDK 7, you can tune your applications thread counts to reduce potential processor resource issues.

Java 8

Java 8 has a few flags that can help the runtime operate in a more container aware manner. These updates were added in the Java 8 Update 131 release which has been available since April 18, 2017.

The update contains improved processor and memory container awareness, and allows for use of experimental VM flags to enable automatic heap adjustment. To unlock this capability simply add the following flags to your java command line options.

java -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -jar app.jar

These experimental flags set the heap size based on the value specified in the container’s sys/fs/cgroup/memory/memory.limit_in_bytes file. You can check out the bug report and work related to this here.

Java 9 & 10

Oracle has signaled that JDK 9 and JDK 10 will be automatically container aware respecting both processor and memory limits. They are also providing manual overrides to allow for disabling or setting these limits manually. There are a number of tickets and work on these features can be tracked on the OpenJDK Bug tracker which you can check out below.

Conclusion

There is still work to be done in order for the JVM to be fully aware of containerization, but so far excellent progress has been made and, more importantly, backported into JDK 8 in order to garner more feedback from the community.

If you find yourself running your Java application in containers and need help check back here frequently for more updates as I start a new series of articles on running java apps with Docker and Kubernetes.