The JVM interprets and executes bytecode at run-time.

JIT compilers


C1, the client compiler, is optimised for fast start-up time.


C2, the server compiler, is optimised for improved overall performance.

Tiered compilation

Tiered compilation (-XX:+TieredCompilation) mixes both compilers to optimise performance:

  • At startup time, JVM code is interpreted and profiling begins to identify hotspots.
  • Hot paths are compiled with C1 to quickly reach native performance.
  • Bytecode is later recompiled using C2 as more profiling information becomes available.

Enabling tiered compilation also enables -XX:+SegmentedCodeCache.

Logging compilation events

Enable the compilation log with -XX:+PrintCompilation. Log entries will look something like:

$compilation_id $attributes ($tiered_level) $method_name $deopt ($size)


  • timestamp is the number of seconds that elapsed between the JVM's startup and compilation completing.
  • compilation_id uniquely identifies the compilation task within the JVM.
  • attributes:
    • % indicates OSR.
    • s indicates synchronisation.
    • ! indicates the method has an exception handler.
    • b indicates compilation blocked execution rather than taking place on a background thread.
    • n indicates the compilation occurred for a wrapper around a native method.
  • method_name is the name of the method being compiled.
  • deopt may detail deoptimisations applied:
    • made non entrant indicates incorrect or incomplete completion, and that future callers won't use this method.
    • made zombie indicates code's not in use and ready for GC.


On-Stack Replacement allows the JVM to replace code on the stack with an optimised version, even during execution of a loop.