JVM Compile Time vs Code Cache

1.4k views Asked by At

I've been benchmarking my app and analyzing it with JMC. I've noticed that under load, it performs quite a bit of JIT compiling. If I send a large amount of transactions per second, the compile time spikes. The compile time always grows proportionally with any heavy load test against the app.

I've also observed that the Code Cache slowly rises as well. So I decided to raise the Code Cache reserve to 500MB to test. Bad move! Now it's spending even more time performing JIT.

Then I explicitly disabled code cache flushing via -XX:-UseCodeCacheFlushing. However, I noticed that the peak Code Cache usage is larger than the current size. This leads me to a couple of questions:

enter image description here

  1. Does the JVM try to cache every JIT compilation?
  2. Why is the peak Code Cache size bigger than the current size even though I disabled flushing?
  3. Is there "temporary" compiled code that's automatically removed after the function ends?
1

There are 1 answers

2
apangin On BEST ANSWER

In HotSpot JVM all JIT-compiled methods stays in CodeCache until they are reclaimed. UseCodeCacheFlushing affects reclamation of cold (but still valid) compiled methods. However, CodeCache may also contain obsolete or invalidated methods ("zombies") which are subject to purge at the next sweep cycle even with -XX:-UseCodeCacheFlushing.

  • In a tiered compilation mode (default since JDK 8) a method may be compiled multiple times with a different level of optimizations. Once an optimized (tier 4) version of a method is installed, the previous version becomes obsolete and can be reclaimed after all activations of that version complete.
  • A speculatively compiled method may become invalid when the speculation fails (e.g. after a new class is loaded). Such method also becomes zombie and can be later reclaimed.
  • Another example is an OSR compilation. This is a version of a method that was compiled specially for transferring execution from interpreter to compiled code while the method is running. Answering your 3rd question, this is a kind of "temporary" method which becomes obsolete after the full version of compiled method is installed and all OSR activations complete.

There is a separate JVM flag -XX:-MethodFlushing to prevent sweeping CodeCache altogether, including zombie methods.