JavaMemory Management

Memory Management

In languages like C or C++, you are responsible for manually allocating memory (malloc) and freeing it (free) when you are done with it — get it wrong, and you leak memory or crash the program by using memory that has already been freed. Java takes a fundamentally different approach: the JVM manages memory for you automatically. You never explicitly free an object; instead, the JVM tracks which objects are still reachable and reclaims the rest (a process covered in depth on the Garbage Collection page).

No manual free() in Java
There is no direct equivalent of C's `free()` in ordinary Java code. Once nothing in your program can reach an object anymore, it becomes eligible for automatic reclamation — you don't decide exactly when that happens, and you don't call anything to trigger it.
Two main memory areas

At a high level, the JVM splits the memory it manages into two main areas that behave very differently.

Area

What lives here

Lifetime & scope

Stack

Method call frames: local variables, method parameters, and references to objects

One stack per thread; a frame is popped as soon as its method returns

Heap

All objects and arrays created with new

Shared across all threads; objects live until no longer reachable, then garbage collected

Every thread gets its own stack, which is why stack data (local variables) is never shared between threads — only heap objects are. This is exactly why data races and the need for tools like synchronized or ConcurrentHashMap are about heap-shared state, never about purely local variables.

Exceptions vs. Errors

It is worth clearly separating two categories of things that can go wrong, because they mean very different things about your program's health.

  • NullPointerException and ArrayIndexOutOfBoundsException are ordinary exceptions — bugs in your program logic (dereferencing something that was never assigned, or indexing past the end of an array). They are expected, recoverable, and normally caught or fixed in code.

  • StackOverflowError and OutOfMemoryError are Errors, not exceptions — they signal that the JVM itself has run out of a fundamental resource (stack space or heap space), typically because of unbounded recursion or a genuine memory leak. They are usually not meant to be caught and recovered from; they indicate something structurally wrong.

A StackOverflowError happens when a thread's call stack grows past its limit — the classic cause is recursion with no base case, where each call pushes another frame onto the stack until it runs out of room. An OutOfMemoryError happens when the heap is full and the garbage collector cannot free enough space to satisfy a new allocation, often because objects are being retained (referenced) longer than intended.

  • The JVM manages memory automatically — there is no manual malloc/free in ordinary Java code.

  • The Stack holds method call frames and local variables, one per thread; the Heap holds all objects, shared across threads.

  • NullPointerException/ArrayIndexOutOfBoundsException are program-logic exceptions; StackOverflowError/OutOfMemoryError are Errors signaling resource exhaustion.

  • How heap memory actually gets reclaimed is the subject of the Garbage Collection page.