Skip to main content

Week 1 Day 1 — JVM, Stack, and Heap

Goal

Today I want the picture of what actually runs when I start a Java program.

Main questions:

  1. What is the difference between JDK, JRE, and JVM?
  2. What happens from .java to running code?
  3. What lives on the stack?
  4. What lives on the heap?
  5. Why does this matter for Spring beans?

1. JDK, JRE, JVM

NameRole
JVMThe engine that runs bytecode. It is a specification plus an implementation (HotSpot on most laptops).
JREJVM plus the class libraries needed to run programs. Modern JDKs ship this as part of the JDK.
JDKThe development kit: compiler (javac), tools (jar, jlink), and the runtime.

Memory sentence:

I compile with the JDK. I run on a JVM. The JRE is the runtime pieces of that JDK.

For this track I install a current JDK 17 or 21. Spring Boot 3 needs 17. Spring Boot 4 needs 17+ and is built for the current LTS line.


2. From source to running program

OrderService.java
│ javac

OrderService.class (bytecode)
│ java

JVM loads classes, verifies bytecode, interprets / JIT-compiles, runs

javac does not produce a native Mac/Linux binary. It produces bytecode. The JVM reads that bytecode.

A class file is not an object. It is a template. The JVM loads the class (into Metaspace in modern Java), then new creates instances on the heap.


3. The stack

Each thread has its own stack.

A stack is a pile of frames. A frame is created when a method is called and dropped when the method returns.

A frame holds:

  • local variables
  • the operand stack the bytecode uses
  • the return address

Local variables include primitives and references.

void place(int quantity) {
int n = quantity; // primitive local: in this frame
Order order = new Order(); // reference local: in this frame
// Order object: on the heap
}

When place returns, the frame is gone. The local n and the local order reference are gone. The Order object stays on the heap only if some other still-living reference points to it.

Memory sentence:

The stack is per-thread and short-lived. It holds frames, not objects.


4. The heap

The heap is the shared object memory of the JVM.

Almost everything created with new lives here:

  • objects
  • arrays (arrays are objects)
  • String objects
  • Spring beans

The garbage collector reclaims heap objects that no thread can reach anymore.

Thread 1 stack Heap
┌─────────────┐ ┌──────────────────┐
│ place() │ │ Order @ 0x1a │
│ n = 2 │────────▶│ id, lines, ... │
│ order ─────┼─────────┤ │
└─────────────┘ └──────────────────┘

Several stacks can point at the same heap object. That is shared mutable state. A singleton Spring bean is exactly that: one heap object, many callers.


5. Where do fields live?

Object fields live with the object on the heap.

class Order {
int quantity; // primitive field: inside the heap object
Customer customer; // reference field: inside the heap object,
// Customer instance: another heap object
}

A primitive local lives in a stack frame. A primitive field lives on the heap as part of its object.

That distinction shows up in interviews: “Are primitives always on the stack?” No.


6. Why Spring cares

A typical Spring Boot app has one JVM process.

The ApplicationContext creates beans once (singleton by default) and keeps references to them on the heap for the life of the process.

@Service
public class OrderService {
public void place() { /* ... */ }
}

Every HTTP request thread that calls OrderService uses the same heap object.

Consequences:

  • Mutable fields on that bean are shared across requests. That is a race unless you protect them.
  • Request data does not belong in singleton fields. It belongs in method arguments or in a request-scoped object.
  • “The service is a singleton” means “one instance on the heap,” not “one thread.”

Memory sentence:

A Spring singleton is one heap object shared by many stacks.


7. Common traps

Trap 1: “Objects live on the stack.”
Local references live on the stack. The object is on the heap.

Trap 2: “The stack is the call history I see in a debugger.”
Related, but the JVM stack is memory: frames and locals, not just method names.

Trap 3: “Garbage collection deletes variables.”
GC reclaims unreachable heap objects. Stack frames disappear when methods return.

Trap 4: “Each request gets its own OrderService bean.”
Not with the default singleton scope. Each request gets its own stack. The bean is shared.


Practice Questions and Answers

Question 1

What is the difference between JDK and JVM?

Answer:

The JVM is the engine that executes bytecode. The JDK is the development kit: compiler, tools, and a JVM to run what you build. I write and compile with the JDK. The running program is bytecode on a JVM.


Question 2

In this method, what lives on the stack and what lives on the heap?

void demo() {
int count = 3;
User user = new User("Ada");
}

Answer:

The frame for demo is on the current thread’s stack. count is a primitive local in that frame. user is a reference local in that frame. The User object and its "Ada" String live on the heap.


Question 3

When demo() returns, is the User object immediately gone?

Answer:

The local reference user is gone with the frame. If nothing else still references that User, it is unreachable and the GC may reclaim it later. It is not deleted at the instant the method returns.


Question 4

Why is a mutable field on a @Service dangerous?

Answer:

The service is one heap object shared by many request threads. A mutable field is shared mutable state. Two requests can interleave writes and corrupt data, or leak one user’s data into another request.


Question 5

Are primitive values always stored on the stack?

Answer:

No. Primitive locals live in a stack frame. Primitive fields live inside the object on the heap.


Memory sentences

I compile with the JDK. I run bytecode on a JVM.

Stacks are per-thread frames. The heap is shared objects.

A Spring singleton is one heap object, many stacks.

Next: Week 1 Day 2 — Primitives, Wrappers, and Boxing