How much time and effort do you put into tuning the JVM for your application? Do you just accept the defaults and run with it? Do you set the max heap size, and that’s good enough? Or do you reach in and really adjust the settings to fit your app perfectly?
Defaults
It seems like most of the time we just run with the defaults. This makes some sense, as the defaults are set in such a way to support the common workloads. Most of the time we just adjust the obvious memory settings. We set the min and max heap sizes. We will perhaps set the max meta space. The default garbage collector, stack size, code cache size, etc. are good enough for our uses.
This is likely where you start. Don’t fix something that isn’t broken. You wait for the performance issues to show up before you concern yourself at all with the other settings. This is a fine approach.
Knowing the Workload
Knowing what type of workload your app is handling does impact how you might tune the JVM. While the defaults might work well for a traditional web app, they may not be the best for a backend integration application. Here you can accept relatively long pauses for garbage collection. So maybe you turn on an different garbage collector, to better optimize your memory usage.
Perhaps you have need for absolutely huge heap sizes, so you even look into competing JVMs that come tuned for those workloads. Or perhaps you need tiny footprints, so you use JVMs that tune for that. Instead of tuning, you need to buy something that is more dedicated to your needs.
Docker
Running your application in Docker is also a different problem. Running microservices in Java. Here you do want a small footprint, but you also want to use the common things. You want the framework to be as commoditized as possible.
However, Java isn’t really set up to run smoothly in this minimalist scenario. Its defaults do not work well inside a Docker environment. We have been very reluctant to dig in and “fix” most of those settings. We set the obvious things, like the heap and meta spaces. Yet we shy away from the more advanced settings like code cache size. Perhaps we allow Docker to occasionally kill the container for using too much memory.
We shy away from those things because we don’t know about them. We haven’t spent the time to learn all the levers we can pull. Even though we can deploy these things quickly, and get rapid feedback on our changes, we still operate with a monolithic mindset. It is scary to change these things, because we might break something.