Stack vs Heap Memory in Java

Naveen AnamaneniUpdated · 5 min read

When a Java program runs, the JVM uses two main kinds of memory for your data. The stack is a small, fast area that each thread has for itself; it holds method calls and their local variables. The heap is a large area shared by all threads; it holds every object and array you create with new. Knowing what goes where explains how references work, why local variables are thread-safe, and what StackOverflowError and OutOfMemoryError mean. In this lesson, you will learn the difference between stack and heap memory.

What Goes Where

Frames and local variables live on the stack; objects live on the heap
Stored on the stackStored on the heap
A frame for each method call in progressEvery object created with new
Local variables of primitive types (int marks = 91)Arrays, strings, records, collections
Local reference variables (the reference itself)The fields of those objects, primitives included
Method parameters and return addressesStatic fields (as part of their class's data)

A local variable such as Student s lives on the stack, but it only holds a reference; the Student object it points to lives on the heap.

Example: The Stack Grows and Shrinks

Let's see an example that shows the stack frames of nested calls, and what happens when recursion never stops.

StackDemo.java▶ Try it
public class StackDemo {
    static int depth = 0;
 
    static void a() { b(); }
    static void b() { c(); }
    static void c() {
        for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
            System.out.println("  frame: " + e.getMethodName());
            if (e.getMethodName().equals("main")) {
                break;
            }
        }
    }
 
    static void forever() {
        depth++;
        forever();
    }
 
    public static void main(String[] args) {
        System.out.println("Frames while inside c():");
        a();
        try {
            forever();
        } catch (StackOverflowError e) {
            System.out.println("StackOverflowError after more than 1000 calls? "
                + (depth > 1000));
        }
    }
}
Output
Frames while inside c():
  frame: getStackTrace
  frame: c
  frame: b
  frame: a
  frame: main
StackOverflowError after more than 1000 calls? true

Explanation: Each call pushes a new frame on the stack, so inside c() the stack holds frames for main, a, b and c (and getStackTrace itself). The loop stops at main; below it are a few frames of the launcher that started the program. When a method returns, its frame is popped. forever() keeps calling itself, so frames pile up until the thread's stack (about 1 MB by default on 64-bit systems) is full, and the JVM throws StackOverflowError. The exact depth depends on the frame size and the stack size.

Differences Between Stack and Heap

StackHeap
HoldsMethod frames, local variables, referencesObjects and arrays
OwnerOne per threadShared by all threads
SizeSmall (about 1 MB per thread by default, -Xss)Large (set with -Xms and -Xmx)
AllocationAutomatic, very fast (move a pointer)new, fast but managed
FreedWhen the method returnsBy the garbage collector, when unreachable
Thread safetyLocal variables are private to their threadObjects can be shared and need care
Error when fullStackOverflowErrorOutOfMemoryError: Java heap space

Common Mistakes

Saying "objects are stored in variables". Variables hold references; objects are on the heap.

Thinking primitives are always on the stack. A primitive field of an object lives on the heap inside that object.

Fixing StackOverflowError by raising -Xss. Usually the real bug is recursion without a proper base case.

Interview Corner

What is the difference between stack and heap memory in Java?

Each thread has its own stack, which stores a frame per active method call with its local variables, parameters and references; frames are created and removed automatically as methods are called and return, and running out causes StackOverflowError. The heap is shared by all threads and stores all objects and arrays, including their fields; memory is reclaimed by the garbage collector once objects are unreachable, and running out causes OutOfMemoryError. A local reference variable lives on the stack while the object it refers to lives on the heap. (The JIT may also avoid heap allocation for objects that never escape a method, using escape analysis.)

Practice

  1. Easy: Write a recursive factorial with a missing base case, run it, and catch the error.
  2. Harder: Run StackDemo with java -Xss256k StackDemo.java and then -Xss4m, printing depth. Explain the difference.

Quick check: Stack vs heap

4 questions
1Where is the object created by new Student() stored?
2Where is a local variable int marks = 91 stored?
3How many stacks are there?
4What error does endless recursion cause?

Key Takeaways

Was this tutorial helpful?

Lesson 433 of 482