Guide
What is a stack frame in the JVM?
What the JVM creates for every method call: the local variable array, the operand stack and frame data, and how bytecode uses them.
Stack frame
JVM specificationStorage for one method invocation: local variables, operand stack and a link to the class's constant pool.
Simply put
A frame is the workspace of one method call. It holds the method's local variables and a small scratch stack for calculations, and it remembers how to get back to the caller.
What a developer sees
A frame lives exactly as long as one method call. Its local variables are the method’s parameters and locals; javac works out how many slots and how deep an operand stack each method needs (locals= and stack= in javap -v).
That is why local variables vanish when a method returns, and why a lambda can only use local variables that never change after they are set (effectively final): it gets a copy of the value, not the frame’s slot.
Picture it
A workspace set up for one task: a notepad for the task’s values and a small scratch pile for working things out, cleared away when the task is done.
- The notepad
The local variable array
- The scratch pile
The operand stack
- Clearing away
The frame is removed when the method returns
Where the picture stops working
A real frame also holds what the JVM needs to return to the caller and to handle exceptions. Its slots hold primitive values and references only, never whole objects. And it is not a literal desk or box: the JIT compiler may keep a frame’s values in processor registers.
Deep dive: the specification and HotSpot in detail
JVMS §2.6: a frame is created each time a method is invoked and destroyed when the invocation completes, normally or abruptly. It contains a , an and a reference to the run-time constant pool of the current method's class (). Their sizes are fixed at compile time (max_locals, max_stack in the Code attribute: 3 and 3 for our main). Only one frame per thread is active: the current frame.
HotSpot's interpreter frame on x86-64 additionally stores the sender's stack pointer, the Method*, the class mirror, the profiling pointer (mdp), the constant pool cache, the locals pointer, the bcp and a monitor block. Compiled frames look different again: values live in registers and one physical frame can represent several inlined methods.
The specification requires
Locals, operand stack, and a reference to the run-time constant pool, with sizes fixed per method.
HotSpot (JDK 25) does
HotSpot: interpreter frames with extra slots (Method*, mdp, cpCache, bcp, monitors); compiled frames with register-allocated values and inlined callees.
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=3, args_size=1
Verified with OpenJDK 25.0.4 · Linux x64
Common misconceptions
Frames grow when a method needs more space.
A frame's maximum size is fixed at compile time and checked by the verifier.
Sources
- SpecJVMS §2.6 Frames(opens in a new tab)
A frame is created per method invocation and destroyed when it completes. · Java SE 25
- Sourceframe_x86.hpp(opens in a new tab)
Interpreter frame layout on x86: method, mdp, cache, locals, bcp, sender sp. · JDK 25 GA (tag jdk-25-ga)
Local variable array
JVM specificationIndexed slots for a method's parameters and local variables; slot 0 is `this` in instance methods.
Simply put
Numbered boxes where a method keeps its parameters and local variables. In main, box 0 holds args, box 1 holds p1 and box 2 holds p2. A box can hold a number or a reference to an object, never the object itself.
Deep dive: the specification and HotSpot in detail
JVMS §2.6.1: an array of variables indexed from 0, sized by max_locals. Each slot holds a boolean, byte, char, short, int, float, reference or returnAddress; long and double occupy two consecutive slots. For instance methods slot 0 holds this; parameters follow in order. Instructions such as aload_1 and astore_2 move values between locals and the operand stack. Local names exist only in the optional LocalVariableTable (javac -g).
LocalVariableTable:
Start Length Slot Name Signature
0 27 0 args [Ljava/lang/String;
10 17 1 p1 LPerson;
12 15 2 p2 LPerson;
Verified with OpenJDK 25.0.4 · Linux x64
Common misconceptions
`p2 = p1` copies the Person object.
It copies the reference value from slot 1 to slot 2 (
aload_1,astore_2). Both slots now refer to the same heap object.
Sources
- SpecJVMS §2.6.1 Local Variables(opens in a new tab)
Array of local variables sized at compile time; long and double use two slots. · Java SE 25
- SpecJLS §12.6 Finalization of Class Instances(opens in a new tab)
Reachability terminology and the (deprecated) finalization mechanism. · Java SE 25
Operand stack
JVM specificationA per-frame LIFO scratch stack: instructions pop their inputs from it and push their results.
Simply put
The JVM is a stack machine. To compute something, it pushes values onto a small stack, and each instruction takes its inputs from the top and puts its result back on top.
Deep dive: the specification and HotSpot in detail
JVMS §2.6.2: each frame has an operand stack whose maximum depth (max_stack) is fixed at compile time. It starts empty. Load and constant instructions push; arithmetic, field and invoke instructions pop operands and push results; invocations pop the arguments and the callee's return value is pushed onto the caller's stack. The verifier proves the stack's depth and types at every instruction.
The operand stack is a model: the template interpreter caches the top value in a register, and compiled code maps stack slots to registers, so no physical operand stack exists in JIT-compiled methods.
0: new #7 // [ Person(uninitialized) ]
3: dup // [ Person, Person ]
4: ldc #9 // [ Person, Person, "Alex" ] ← depth 3 = max_stack
6: invokespecial #11 // [ Person ] (<init> consumed two values)
9: astore_1 // [ ] (reference stored in local 1)
Verified with OpenJDK 25.0.4 · Linux x64 (instructions from javap; stack states follow JVMS §6.5)
Common misconceptions
The operand stack is the same as the thread's stack.
Each frame has its own small operand stack inside it. The thread's JVM stack holds the frames.
Sources
- SpecJVMS §2.6.2 Operand Stacks(opens in a new tab)
LIFO operand stack with a maximum depth fixed at compile time. · Java SE 25
- SpecJVMS §6.5 new(opens in a new tab)
Creates a new object; may trigger resolution and initialization of the class. · Java SE 25
- SpecJVMS §6.5 invokespecial(opens in a new tab)
Invokes instance initialization methods, private methods and superclass methods. · Java SE 25