Concepts · Java fundamentals

JVM internals

Class loading, runtime memory areas, bytecode and the JIT.

From source to running code

javac compiles .java to platform-independent bytecode (.class). The JVM loads it, verifies it, and runs it, first in the interpreter and then as native code once the JIT compiles the hot paths.

Class loading

Three steps: load (find the bytes), link (verify → prepare static fields with defaults → resolve symbolic references), initialise (run static initialisers, once, on first active use).

Loaders delegate parent-first: Bootstrap (core java.*) → Platform → Application (your classpath). A class is identified by its name plus its loader, so the same class loaded twice by different loaders is two different types.

Runtime memory areas

AreaShared?Holds
Heapall threadsevery object and array; managed by the GC
Stackone per threada frame per method call: local variables, operands, return address
Metaspaceall threadsclass metadata (native memory since Java 8, replaced PermGen)
PC registerone per threadthe current bytecode instruction
Native method stackone per threadframes for native (JNI) calls

StackOverflowError = a thread’s stack is full (usually deep recursion). OutOfMemoryError = the heap or metaspace can’t grow.

JIT compilation

Methods start interpreted. The JVM counts calls and loops; hot code is compiled by C1 (fast, light optimisation), then C2 (slower, aggressive: inlining, escape analysis, loop unrolling). This tiered compilation is why Java “warms up”.

Interview angles

  • Why is Java “write once, run anywhere”? Bytecode + a JVM per platform.
  • Where do local variables vs objects live? Primitives and references on the stack; objects on the heap.
  • What is escape analysis? If an object never escapes a method, the JIT can skip the heap allocation (scalar replacement).