Fabric8 has really good base java images[1] with a script that simply sets environment variables with right GC and CPU parameters before launching Java, with nice sane defaults.
Heavily encourage anyone running Java in containers to use their base image, or for larger organizations to create standard base image dockerfiles that set these JVM envvar parameters. A simple contract is: ENTRYPOINT belongs to the base image, CMD belongs to downstream application images (unless something else essential).
Just don't use vanilla "FROM openjdk:8-jre" and expect it to work. That's the worst way to kill application performance and reliability in a container.
I disagree. They seem mostly targeted at low-end cloud providers who overcommit on memory and ignore application response time (gc latency). And they don't even do a good job at this.
Their configuration uses the ParallelOld gc and tunes it to aggressively shrink the heap. What that means they don't care about frequent and long gc pauses (unless you're running small heaps below 1 GB). They just care about reducing the memory footprint of the application. On multi gigabyte heaps you accept full GCs that take several seconds. They increase the number of concurrent GC threads to the number of cores. This defeats the whole purpose of the concurrent GC threads which are supposed to run concurrently with your application without stopping it. That value should be below the number of cores.
gc logging does not work on Java 9 or Java 10
If you really care about reducing memory usage you probably should do this in addition:
-XX:-TieredCompilation hurts startup perfromance, but we just established that we don't care about performance so that's fine, but easily takes 35% out of code cache
-Xss512k cuts the thread memory usage by half, this can usually be done without any issues, often -Xss256k works as well. We run Spring inside a full profile Java EE application server with -Xss256k.
And finally the most important option of them all -XX:HeapDumpOnOutOfMemoryError is missing. You absolutely, positively need this, always. It's the only way to debug OutOfMemoryErrors.
We tried those flags in the beginning since it was introduced in docker openjdk image[1].
When we dug in further, we find its just not trouble free (i.e. experimental). The default is to use 1/4th of RAM which is entirely inefficient [2]. The "MaxRAMFraction" parameter allows to specify 1/n fraction and not possible to efficiently use 65% or 75% of memory. The only place to start is to set MaxRAMFraction=2 and that already means only 50% of memory is used for heap. That produces a lot of wastage. A lot of resource efficiency is gained by starting with 65% or 80%.
OpenJDK 10 is introducing a new option "MaxRAMPercentage" [3] and that goes closer to making a script unnecessary.
TL;DR - The default flags are still experimental in JDK 8/9, and deemed to be better on Java 10. A script is just better for consistency.
+1 for Fabric8. It makes running Java in containers much more pleasant, and provides a complete opinionated ecosystem, if that's desired. I work at an enterprise shop that is a Red Hat customer (so we get commercial support on this stuff), and it has made our lives much easier in many respects.
Heavily encourage anyone running Java in containers to use their base image, or for larger organizations to create standard base image dockerfiles that set these JVM envvar parameters. A simple contract is: ENTRYPOINT belongs to the base image, CMD belongs to downstream application images (unless something else essential).
Just don't use vanilla "FROM openjdk:8-jre" and expect it to work. That's the worst way to kill application performance and reliability in a container.
1: https://github.com/fabric8io-images/java/blob/master/images/...