[!NOTE] In legacy C/C++, if you allocated memory for 10,000
Carobjects, it was your explicit responsibility to order the CPU tofree()that memory when you finished. If you forgot, the RAM filled up endlessly until the computer suffered a Blue Screen of Death. This is called a "Memory Leak".
Java completely automated this with the Garbage Collector (GC), heavily influencing the design of C# and Go.
The Heap Memory
Every time you execute the new keyword (e.g., new Car()), Java allocates physical space in an area of RAM called the Heap.
public void processOrders() {
// 1. Spawns an object on the massive Heap.
// The 'report' variable on the Stack is just a pointer pointing to the Heap object!
OrderReport report = new OrderReport();
report.compile();
} // 2. Method ends. The 'report' pointer is destroyed.
When the method finishes, the report pointer is destroyed. But the massive OrderReport object is still sitting entirely intact out on the Heap, consuming megabytes of RAM!
The Tracing Garbage Collector
Because no active variables are currently pointing to that OrderReport object, it is officially orphaned. It is impossible for your code to ever access it again.
A daemon thread called the Garbage Collector sleeps in the background. Periodically, it wakes up and pauses the application.
- Mark Phase: It traces every single active variable in your program, painting the objects they point to as "Alive".
- Sweep Phase: It scans the entire Heap array. Any orphaned object that the Mark phase didn't paint is annihilated. The RAM is recovered!
The Risk of Memory Leaks in Java
Wait, if Java automatically sweeps orphaned objects, how can a Java Server suffer a Memory Leak?
If you maintain a massive static (global) ArrayList, and endlessly add items to it, they are technically never orphaned.
public class Cache {
// A single global list
public static ArrayList<User> staticUserCache = new ArrayList<>();
public void loginUser() {
// We endlessly add users, but NEVER call .remove()
staticUserCache.add(new User());
}
}
Because the staticUserCache variable is permanently alive (it's attached to the Class itself), the millions of User objects inside it are never considered "orphaned". The Garbage Collector refuses to touch them. Eventually, your JVM crashes with a catastrophic OutOfMemoryError.
Memory Leaks Usually Mean Accidental Reachability
In Java, objects are collected when they are unreachable. A memory leak usually means objects are still reachable through some long-lived reference even though the application no longer needs them.
Common Leak Sources
- Static collections that keep growing.
- Caches without size or time limits.
- Listeners or callbacks that are registered but never removed.
- ThreadLocals that keep references longer than expected.
Cache With a Limit
Map<String, String> cache = new LinkedHashMap<>(100, 0.75f, true) {
protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
return size() > 100;
}
};
Real production systems often use dedicated cache libraries, but the principle is the same: long-lived memory needs limits.
Common Mistakes
- Calling
System.gc()and expecting predictable cleanup. - Assuming garbage collection prevents every memory leak.
- Keeping unnecessary references in static fields.
- Ignoring heap usage until the application crashes.
Mini Practice
Create a list in a loop and observe memory usage conceptually. Then explain why a local list can be collected after the method ends but a static list may stay forever.
Practice Lab: Reachability Experiment
Reason about which objects can be garbage collected and which stay reachable.
- Create a method that builds a local
ArrayListof temporary objects. - Let the method finish and explain why the list can become unreachable.
- Create a static list and keep adding objects to it.
- Explain why those objects remain reachable.
- Add a clear method that removes unneeded items from the static list.
Goal: Understand that Java memory leaks usually come from objects that remain reachable too long.
Revision Checkpoint
- Heap: Memory area where objects live.
- Reachable: Object can still be accessed through references.
- Garbage: Object no longer reachable.
- GC: Reclaims unreachable object memory.
- Leak risk: Long-lived references can keep unused objects alive.
Before the quiz: Explain how a static list can cause a memory leak in Java.