π§ Memory Management & Garbage Collection in Java
This guide explains how Java manages memory using Stack and Heap, how objects and references work, and how the JVM performs Garbage Collection (GC) to free unused objects.
Table of Contents
- Stack vs Heap
- Stack Memory
- Heap Memory
- String Pool
- Memory Allocation Example
- Object Reachability & GC
- Garbage Collection Algorithms
- Young Generation vs Old Generation
- GC Types
- Important Concepts
1. Stack vs Heap
Java memory is divided into two main regions:
| Aspect | Stack | Heap |
|---|---|---|
| Stores | Method frames, local variables, primitive values, object references | Objects, arrays, String pool |
| Scope | Per-thread (each thread has its own) | Shared across all threads |
| Allocation | LIFO order | Dynamic (no strict order) |
| Deallocation | Automatic when method ends | Via Garbage Collector |
| Error when full | StackOverflowError |
OutOfMemoryError |
| Speed | Very fast | Slower than stack |
2. Stack Memory
Stack stores:
- Method call frames (scope)
- Local variables
- Primitive values (
int,double,boolean, etc.) - References to objects (the reference itself, not the object)
Key Behaviors:
β LIFO (Last In, First Out) β Variables exist only within their scope
β Automatic cleanup β When a method ends, its stack frame is popped and local variables are removed
β οΈ StackOverflowError β Occurs if stack becomes full (common in infinite recursion)
Example:
void myMethod() {
int x = 10; // Stack: primitive stored here
Person p = new Person(); // Stack: reference stored here
}
// When myMethod() ends β stack frame is popped β x & p reference removed
3. Heap Memory
Heap stores:
- Objects created using
newkeyword - Arrays
- String pool (String interned values)
Key Characteristics:
β Shared across threads β All threads can access heap objects
β Garbage collected β Objects freed when no longer referenced
β οΈ OutOfMemoryError β Occurs if heap becomes full
Example:
Person p = new Person(); // Reference 'p' in stack, object in heap
String s = "Hello"; // Literal "Hello" in String pool (heap)
4. String Pool
String literals are stored in a special area called the String Constant Pool (inside heap).
String s1 = "Memory"; // Created in String pool
String s2 = "Memory"; // Points to SAME object in pool
String s3 = new String("Memory"); // NEW object in heap (not in pool)
System.out.println(s1 == s2); // true (same reference)
System.out.println(s1 == s3); // false (different objects)
5. Memory Allocation Example
Code:
int primitiveVar = 10;
Person personObj = new Person();
String stringLiteral = "Memory";
MemoryManagement memObj = new MemoryManagement();
memObj.memoryManagementTest(personObj);
UML Class Diagram:
Memory Layout Diagram:
PlantUML Generated Diagram:
What Happens in Memory:
| Variable | Storage Location | Details |
|---|---|---|
primitiveVar = 10 |
Stack | Primitive value stored directly |
personObj |
Stack β Heap | Reference in stack, object in heap |
stringLiteral = "Memory" |
String Pool | Literal stored in pool (heap area) |
memObj |
Stack β Heap | Reference in stack, object in heap |
When memoryManagementTest() ends:
- Its local variablesβ references are removed from stack
- Heap objects may become unreferenced
- Garbage Collector later cleans up unreachable objects
6. Object Reachability & GC
When Does an Object Become Garbage Collectable?
An object is eligible for garbage collection when it becomes unreachable from GC roots.
Common Ways Objects Become Unreachable:
β Assigning to null
Person obj = new Person();
obj = null; // Object becomes unreachable
β Reassignment
Person obj1 = new Person();
Person obj2 = new Person();
obj1 = obj2; // Old obj1 becomes unreachable (eligible for GC)
β Method scope ends
void test() {
Person obj = new Person();
} // When test() ends β reference removed β object may become unreachable
7. Garbage Collection Algorithms
Mark β Sweep β Compact
The JVM performs garbage collection in three main steps:
Step 1: Mark
- Identifies all reachable objects from GC Roots
- Marks them as βliveβ
Step 2: Sweep
- Deallocates unmarked (unreachable) objects
- Frees heap memory
Step 3: Compaction
- Moves live objects together to reduce fragmentation
- Creates contiguous free space
GC Roots (What Keeps Objects Alive):
Objects are considered alive if reachable from:
- Local variables in active threads
- Static variables
- Class references
- Thread objects
8. Young Generation vs Old Generation
Heap Structure:
The JVM heap is divided into generations:
βββββββββββββββββββββββββββββββββββ
β Young Generation β
ββββββββββββββββ¬βββββββββββββββββββ€
β Eden β Survivor (S0,S1)β
ββββββββββββββββ΄βββββββββββββββββββ
β (promotion)
ββββββββββββββββββββββββββββββββββββ
β Old / Tenured Generation β
ββββββββββββββββββββββββββββββββββββ
Metaspace (Non-Heap) - Class metadata
Minor GC (Young Generation):
β Runs frequently and quickly
β Cleans up short-lived objects in Eden space
β Moves surviving objects between Survivor spaces (S0 β S1)
β Tracks object age (how many GC cycles survived)
Promotion to Old Generation:
When an objectβs age exceeds threshold (typically 8):
- Object promoted from Young β Old generation
- Reduces Young generation size
Major/Full GC (Old Generation):
β Runs less frequently but heavier cleanup
β Higher pause time (application stops)
β Cleans up old long-lived objects
Metaspace:
β Stores class metadata and static information
β Not part of heap (non-heap memory)
β
Replaced PermGen in Java 8+
9. GC Types
Different garbage collectors with different trade-offs:
Serial GC
- Single-threaded
- Stop-the-world pauses
- Best for: Small applications, limited CPU
Parallel GC (Default in Java 8)
- Multiple GC threads
- Improved throughput
- Best for: Multi-core systems, server applications
CMS (Concurrent Mark Sweep)
- Reduced stop-the-world time
- Attempts concurrent work with application
- Not fully pause-free
- Best for: Low-latency applications
G1 GC (Garbage First)
- Balances throughput and latency
- Includes automatic compaction
- Aims to limit pause time
- Best for: Large heaps, modern systems
10. Important Concepts
Stop-The-World (STW)
Many GC phases pause application threads:
- Serial GC pauses more
- G1 GC tries to limit pause time
- Longer pauses = noticeable application lag
Java Memory Leaks
Even with automatic GC, leaks can occur when:
- References unintentionally kept alive
- Static maps growing unbounded
- Event listeners not removed
- Thread-local variables not cleaned up
Definition: A memory leak is when an object is no longer needed but remains reachable, preventing GC from freeing it.
System.gc() is Optional
System.gc(); // Just a SUGGESTION, not a command
- JVM may or may not run GC
- GC timing depends on memory pressure and implementation
- Rely on JVM to manage GC automatically
Weak vs Soft References
Strong Reference (Default)
Person p = new Person(); // GC won't delete while reachable
Weak Reference
WeakReference<Person> wp = new WeakReference<>(new Person());
// GC can collect immediately during next GC cycle
Soft Reference
SoftReference<Person> sp = new SoftReference<>(new Person());
// GC collects only when memory is desperately needed (cache scenarios)
Quick Summary & Revision
| Concept | Key Points |
|---|---|
| Stack | Per-thread, LIFO, stores primitives & references, fast deallocation |
| Heap | Shared, stores objects, freed by GC, slower allocation |
| String Pool | Special heap area for literal strings |
| Young Gen | Eden + Survivor spaces, frequent minor GC |
| Old Gen | Long-lived objects, major GC less frequent |
| Mark-Sweep-Compact | GC identifies reachable objects, removes unreachable, compacts memory |
| Stop-The-World | Application pauses during GC phases |
| Memory Leak | Object unreferenced but still reachable = GC canβt clean |
| Strong Reference | Keeps object alive |
| Weak Reference | GC can collect anytime |
| Soft Reference | GC collects under memory pressure |