Step 1 Source becomes bytecode
You write .java files; the compiler javac turns them into .class files containing bytecode — a compact instruction set for an imaginary stack machine. Bytecode is not native CPU code; it is portable, which is the whole "write once, run anywhere" idea. The JVM is what reads it.
Pick a snippet to disassemble
javap -c would show)Each line is one operation on an operand stack: push values, do arithmetic, call methods, store results. The JVM executes these one by one.
Step 2 Class loading & the delegation chain
Classes are loaded lazily, the first time they are needed. The JVM uses a hierarchy of class loaders, and each one asks its parent first (the parent-delegation model) so core classes can never be spoofed by your code. Loading happens in three phases: load the bytes, link (verify + prepare + resolve), then initialize (run static initializers).
Request a class — watch delegation walk up, then load walk down
Click a class above. A loader delegates upward first; whichever loader owns that class loads it.
Step 3 Interpret first, then JIT-compile the hot paths
The JVM starts by interpreting bytecode — simple and instant to start, but slow. Meanwhile it counts how often each method runs. Once a method gets "hot" (crosses an invocation threshold), the Just-In-Time compiler (HotSpot's C1/C2) compiles it to optimized native machine code, so later calls run at full speed. This is why a JVM program speeds up after it "warms up".
Call a method repeatedly and watch it get compiled
Below the threshold the method is interpreted. After ~10,000 calls HotSpot compiles it; per-call cost drops sharply.
Step 4 The stack and the heap
Each thread has its own stack: a frame is pushed for every method call (holding its local variables and partial results) and popped when it returns. All objects live on the shared heap; variables on the stack just hold references (pointers) into it. The stack is tiny and fast; the heap is large and garbage-collected.
Call methods and allocate — see frames and objects
Returning pops the top frame. Objects it created stay on the heap until nothing references them — that is the garbage collector's job.
Step 5 Garbage collection
You never free() in Java. The GC periodically finds objects that are no longer reachable from your live references and reclaims their memory. Most collectors are generational: new objects go in the young generation (collected often and cheaply, since most die young); survivors are promoted to the old generation (collected rarely).
Allocate, drop references, then collect
Allocate some objects, drop a few references, then run GC: unreachable objects vanish and survivors are promoted to the old generation.
Step 6 Glossary
| Term | In one sentence |
|---|---|
bytecode | Portable instructions in a .class file that the JVM executes. |
JIT (HotSpot) | Compiles frequently-run bytecode to native code at runtime for speed. |
class loader | Finds and loads classes on demand, delegating to its parent first. |
heap | Shared memory where all objects live; managed by the GC. |
stack frame | Per-call slice of a thread's stack holding locals and operands. |
GC | Reclaims unreachable objects automatically; usually generational. |
JDK / JRE | JDK = tools + compiler to build; JRE = just enough to run. |
The full loop: javac → bytecode → load → verify → interpret → JIT-compile hot paths, with the heap and GC handling memory throughout. The same machine runs any language that emits JVM bytecode.