Under The Hood
backend java JDK 21+ (HotSpot tiered compilation, GraalVM JIT)

JIT Compilation: Tiered Compilation, C1, C2, GraalVM

Last updated
Prerequisites:
Java bytecode and class loading basics
Understanding of interpretation vs compilation
  • java
  • jit
  • c1
  • c2
  • graalvm
  • compilation
  • hotspot

Read at your depth

The practical view

The JVM starts by interpreting bytecode, then the JIT compiler compiles hot methods to native machine code at runtime. HotSpot uses tiered compilation by default: C1 (client compiler) compiles quickly with moderate optimization, and C2 (server compiler) does deep optimizations for very hot methods. You can observe with -XX:+PrintCompilation and control with -XX:TieredStopAtLevel. GraalVM provides an alternative JIT (and an AOT compiler for native images). JIT means Java code gets faster the more it runs — benchmarks must warm up.

The same idea in other frameworks

react equivalent
N/A — JVM runtime concern.

Legacy vs modern

Interpreted baseline vs tiered JIT-compiled execution

Running cold code interprets bytecode; hot methods get compiled to native machine code with profiling-driven optimization.

before → after
Single-tier naive assumption
// ❌ OLD: assuming all Java code runs as compiled native code from the start
Warmup before measuring (tiered JIT)
for (int i = 0; i < 10_000; i++) sum(1_000); // ✅ NEW: warm up so C1/C2 compile

Interview gotchas

Context

This tests the interpretation→profiling→compilation model — interviewers want the thresholds and tier progression, not just 'the JIT compiles hot code'.

The mechanical answer

The JVM starts by interpreting bytecode (level 0) so execution begins immediately. The interpreter (and later C1 with profiling) collects per-method data: invocation counts, backedge counts (loops), and type profiles of call sites, stored in method data objects. When a method's counters cross the compilation thresholds (e.g. -XX:CompileThreshold, plus tiered thresholds), it is queued to the compiler broker: first C1 with profiling (tier 2/3) for quick native code, then, if still hot, C2 (tier 4) for deep optimization using the collected profile. This lazy, profile-guided progression is why cold code is interpreted (fast startup), warm code gets quick compilation, and hot code gets maximal optimization — and why microbenchmarks must include warmup to reflect steady state.

Trap

The naive answer is 'the JIT compiles everything at startup'. Compilation is demand-driven and profile-guided, happening after thresholds. Another trap: thinking compiled code is permanent — deoptimization (uncommon traps) reverts to interpretation when a guarded optimization (e.g. an inlined call's assumed type) is violated. Candidates who mention thresholds, MDO profiling, and deoptimization show real understanding.

Under The Hood — a multi-depth technical interview hub.

Third-party licenses Press ⌘ K to search.