Java Heap vs Stack

Preface: Java Memory Management

Memory allows programs to run efficiently. In-memory operations are significantly faster than disk operations. Using memory, applications can hold references to objects and data structures without having to perform costly read/write operations to a database or remote service.

Memory is a limited resource. An OS only has so much memory available to run applications. When you run a Java application, the OS allocates a specified amount of its memory to the JVM for running your application.

All of the classes, methods, variables, etc. you define in your Java application rely on memory. When you create a new object in Java, memory is used to "save" the object for use in your program. If your application uses too much memory, your application can crash...

Fortunately, Java handles the allocation and use of memory for you. Unlike other programming languages, Java automatically releases memory for you when objects, variables, etc. are no longer being used. The compiler also optimizes your code to maximize the efficiency of memory being used by your application.

This does not mean you won't still run into memory management issues using Java. If you've ever seen a StackOverflowError or OutOfMemoryError exception and your application crashes then you've experienced the pain of poor memory management.

This is why it's important to understand how Java memory management works under the hood. While the details behind how Java handles memory is rather complicated and overwhelming, understanding the difference between Java Heap vs Stack is a great way to explore what's happening under the hood...

Understanding Heap vs Stack with an example...

Let's take the following simple Java program as a starting point:

public class MyClass  {
    private static void printObject(Object param) {
        String str = param.toString();
        System.out.println(str);
    }
    public static void main(String[] args) {
        int i = 1;
        Object myObject = new Object();
        printObject(myObject);
    }
}
    private static void printObject(Object param) {
        String str = param.toString();
        System.out.println(str);
    }
    public static void main(String[] args) {
        int i = 1;
        Object myObject = new Object();
        printObject(myObject);
    }
}

This simple program creates a new Object and prints the string representation.

For every variable we declare, for every object we create, for every method we call, the JVM will allocate memory to either Stack Memory or Heap Space.

Confused? Read on...

Java Heap Space

The Heap Space is a global memory space for storing objects and classes at runtime. When we create a new object via new Object() this stores the newly created object in the heap space. Similarly, our printObject method stores the String str in the heap space.

When our program executes, the methods hold references to these objects.

Why the Heap Space?

The Heap Space allows for the dynamic allocation/deallocation of memory. It provides a lean approach to handling memory as objects can be efficiently referenced and reused when possible. Without heap space, objects would be allocated to memory more than necessary and dynamic memory management wouldn't be possible.

Garbage Collection

Garbage collection is the automated mechanism by which the Heap releases memory when objects are no longer being used. The garbage collection process is rather complicated and outside the scope of understanding the basics of Heap vs Stack but here is a brief description of how it works:

Garbage collection is an automatic process. It's implementation varies based on which JVM you are using, however some common concepts apply to these variations.

First, the garbage collector marks any unreferenced objects not being used by the application. Then the collector deletes these unused objects from memory.

The garbage collector categorizes objects by age so that it can efficiently remove most short-lived objects. These categories include:

young generation: newly created objects

old generation: objects that survive multiple garbage collection "cycles" are moved to this stage

permanent generation: metadata including classes and method are stored here

A "minor garbage collection event" will remove unused objects from the young generation whereas a "major garbage collection event" will remove objects from the older generations.

By categorizing objects by age, the garbage collector is able to free up memory efficiently and automatically. This allows Java developers to write code without managing memory allocation manually.

Confused? Be sure to check out Garbage collection in Java.

Java Stack Memory

Stack memory is used for the execution of a single thread in Java. It stores primitive types like our int i and references to the objects stored in the Heap space.

Stack memory follows a last in first out (LIFO) approach to memory access. When our program executes, the main() method gets invoked. This results in a block of memory being added to the stack. This memory block will hold the primitive variable i along with a REFERENCE to the newly created new Object(). Remember that the object itself is stored in the heap space.

Notice that the main() method invokes the printObject() method. When this happens, a new memory block is added to the top of the stack. This memory block will hold a reference to the str.

When the printObject() method finishes execution, the memory block is removed from the stack and becomes free.

IMPORTANT: Notice how our main() method passes our newly created myObject to the printObject() function...

printObject(myObject)

When this printObject() method gets invoked, it creates its own reference for the passed in param. While both methods create their own references to myObject, both methods reference the same object stored in the heap space..

This important fact sheds light on the heap and stack work together to efficiently manage memory in Java.

Java Heap vs Stack

The Heap is a global space of memory. It gets allocated by the JVM when your program starts and is used as long as the application is running. Objects stored in the heap space are available anywhere in the application. This also means the heap space IS NOT thread safe.

The stack IS thread safe because it exists on a per thread basis. The stack releases memory immediately after a method finishes execution.

Memory accessed through the heap space is complex. Different spaces (young generation, old generation) are used to essentially mark the lifetime of resources. This is fundamental to the garbage collection process but also very complex.

Memory accessed through the stack is simple. For every method that gets invoked, a new memory block is added to the top of the stack. When the method is done executing, the block is freed and "popped" off the top of the stack. This refers to the LIFO approach to Stack memory access.

Conclusion

Heap space is not thread safe while Stack memory is thread safe.

Heap space is global while Stack memory is local to current method/thread.

Heap space access is determined by a young generation/old generation tracking system while Stack access follows a simple LIFO pattern.

Heap space stores all objects created by Java application while Stack memory stores only primitive types and references to those objects.

Heap space is slower to access than Stack memory.

Your thoughts?

|

great read

|

great read. super curious who came up with this whole garbage collection thing :)

|

simple explanation..THANK YOU!