The JVM does great stuff to let our Java applications run the fastest way possible. Most of the time, you don’t have to care about the internals, but if you really need to get the best performance, you need to take into account how JVM works. It’s not the goal of this article to give a detailed introduction to this topic but merely to show how our design can impact performance and how you can work around some issues which arise.
An important aspect of performance optimization is inlining, i.e. the JIT replaces a method call with the code that will be executed by the method. For that to work, the method must be short, and it must be clear what the method is called. This is unfortunately not trivial as basically all methods can be overloaded, so the JVM does some run-time analysis and then makes some predictions. It basically distinguishes between monomorphic call sites, which always call the same method; bimorphic ones, which are optimized for two different targets; and call sites calling with more than two targets, which are called megamorphic, where fewer optimizations are applied. This analysis and the resulting optimization are done for each call site individually.