From source text to running machine code
The JVM is not a compiler and not an interpreter — it is both, plus a memory manager, a linker and a security check, wrapped in one process. Click any stage to see what it actually does.
The machine, in one picture
The three subsystems below are the whole of a JVM. Everything else in this page is a zoom into one of them.
The same method, twice
javac does far less than people expect: it checks types, desugars a little syntax and
emits a stack machine program. Almost every optimisation you have heard of happens later, at run time.
Nothing in the right-hand column mentions a register or an x86 instruction.
That is the portability trick: the .class file is a program for a machine that does not exist,
and every JVM is an implementation of that machine.
Loading a class is a negotiation, not a file read
Ask for a class and the request travels up the loader chain before anything is read from disk. Pick a class and watch the delegation.
Delegation log
Then five phases, in order
Only the first phase touches the file system. The rest are the JVM convincing itself that the bytes are safe to run.
What is actually in those bytes
A .class file is a single flat structure with no padding and no alignment.
Hover or tap a field to read it.
Some memory is shared. Some of it is yours alone.
The single most useful thing to know about JVM memory is which side of this line each area sits on. Add threads and watch which boxes multiply.
Shared by all threads
One set per thread
The JVM is a stack machine. Here it is, running.
No registers, no variables in expressions — just an operand stack you push onto and pop from. Step through a real method and watch every push.
Java
Bytecode Code attribute of the method
pc register per thread
Operand stack current frame
Local variables current frame
JVM stack frames, innermost first
Output
Code that gets used gets rewritten
HotSpot starts every method in the interpreter and counts. Cross a threshold and the method is compiled — twice, by two different compilers, for two different reasons.
Illustrative. Real speedups depend entirely on the code.
- Current tier
- 0 — interpreter
- Compiled by
- nobody yet
- Code cache
- empty
- Deoptimisations
- 0
Compiler log what -XX:+PrintCompilation would show you
Most objects die young, and the collector is built around that
Allocate objects and watch Eden fill. When it is full, everything still alive is copied out — and copying is cheap precisely because almost nothing survives.
- Objects allocated
- 0
- Young GCs
- 0
- Full GCs
- 0
- Promoted to old
- 0
- Collected
- 0
- Simulated pause
- 0.0 ms