Object lifetime & garbage collection in Java
Unreachable objects are collected automatically; no destructors; finalize is deprecated.
No delete in Java
Java has **no delete, no free and no destructors. A garbage collector** (GC) automatically reclaims the memory of objects your program can no longer use.
Reachability is everything
The GC starts from roots — local variables of running methods, static fields — and follows references. Anything it can't reach is garbage, *eligible* for collection. When it's actually collected is up to the JVM; System.gc() is only a hint.
Car c = new Car("A");
c = null; // Car A: unreachable nowWhich car is garbage?
Car x = new Car("X"); Car y = x; x = new Car("Z"); y = null; — which Car objects are eligible for garbage collection?
Think about it, then reveal the answer
Only X. At first both x and y point to X. Then x moves to the new Z, and y = null drops the last reference to X. Z is still reachable through x.
Cycles are no problem
Two objects that reference each other, but that nothing else can reach, are still garbage. Java traces from the roots instead of counting references, so an isolated cycle is collected — pure reference counting would leak it.
finalize() is a trap
finalize() may run late or never, and it's deprecated for removal (JEP 421, Java 18). Don't rely on it to close files or connections. Use try-with-resources to release them deterministically.
try (var in = Files.newInputStream(p)) {
// use in
} // closed here, guaranteedLeaks still happen
The GC frees only unreachable objects. If a reachable collection keeps references you no longer need — say a static list that only grows — nothing is ever freed, and eventually you hit OutOfMemoryError. That's a Java memory leak.
static List<byte[]> cache = new ArrayList<>();
// cache.add(...) forever -> OOMIn real projects
Production memory leaks are almost always "forgotten but reachable": caches without limits, listeners never removed, sessions never expired. Engineers find them with heap dumps, and tune collectors like G1 (the default) or ZGC for low pause times.
Key takeaways
- Unreachable objects are collected automatically
- Collection time is up to the JVM, not you
- Cycles of unreachable objects are collected too
- Reachable-but-forgotten objects still leak memory
ZGC, one of the JVM's garbage collectors, is designed to keep pause times under a millisecond — even with heaps of many terabytes.
Practice questions
When does an object become eligible for garbage collection?
- When no live thread can reach it through any chain of references
- Immediately when its variable goes out of scope
- Only when System.gc() is called
- When its reference count drops to exactly zero
Check your answer
When no live thread can reach it through any chain of references. Reachability, not scope or counting, is what matters. The GC traces from roots like local variables and static fields; anything it cannot reach is garbage.
After these lines run, which Car objects are eligible for garbage collection?
Car a = new Car("A");
Car b = new Car("B");
a = b;
b = null;- Only Car A
- Only Car B
- Both cars
- Neither car
Check your answer
Only Car A. a = b drops the only reference to Car A. b = null clears one reference to Car B, but a still points to it, so B is reachable.