Learning goals
By the end of this chapter you should be able to:
- Define garbage in terms of reachability from GC roots
- Explain young vs old generations and why minor GC is frequent
- Compare collector families (G1, ZGC, Parallel) at a high level
- Connect application patterns (caches, listeners, thread locals) to memory leaks
Why GC follows memory structure
In the previous chapter you placed objects on the heap and saw generations (Eden, survivors, old). Garbage collection is how the JVM reclaims unreachable objects in that heap — without you calling free.
String temp = new String("data");
temp = null; // prior String may become eligible for collection
Eligible ≠ collected immediately. The GC runs when allocation pressure or explicit hints (System.gc() — usually ignore) trigger a cycle.
The sections below walk through what gets collected, when pauses happen, and which collector fits which workload — building on your heap layout notes.
Overview
In C/C++ you call free() yourself. In Java, the garbage collector (GC) does it for you — it scans the heap, finds objects nothing is pointing to anymore, and reclaims their memory.
The trade-off: the JVM occasionally pauses your app to do this. Interview questions are mostly about how the GC decides what to collect, when it pauses, and how to pick the right collector for your workload.
Table of contents
- What “garbage” means
- Heap layout: young vs old generation
- Minor GC vs Major GC vs Full GC
- Stop-the-world pauses
- The GC algorithms
- Tuning basics
- Common interview questions
- Summary
1. What “garbage” means
An object is garbage when no live reference reaches it from a GC root (local variables, static fields, thread stacks, JNI refs).
String a = new String("hello"); // object reachable from local 'a'
a = null; // now the "hello" object is unreachable → eligible for GC
The GC’s job: find these unreachable objects and reclaim the memory.
2. Heap layout: young vs old generation
The JVM heap is split into generations because of one observation — most objects die young. So the JVM collects new objects often (cheap) and old ones rarely (expensive).
+---------- Heap ----------+
| Young Generation |
| ├─ Eden | <- new objects land here
| ├─ Survivor S0 |
| └─ Survivor S1 |
+--------------------------+
| Old (Tenured) Generation| <- long-lived objects
+--------------------------+
How an object moves:
newputs it in Eden.- When Eden fills → Minor GC runs. Surviving objects move to a Survivor space.
- After surviving a few Minor GCs (the tenuring threshold), the object gets promoted to Old.
A separate area called Metaspace holds class metadata (replaced “PermGen” in Java 8+). It lives outside the heap.
3. Minor GC vs Major GC vs Full GC
| Type | What it collects | Speed | Pause |
|---|---|---|---|
| Minor GC | Young generation only | Fast (ms) | Short stop-the-world |
| Major GC | Old generation | Slow (often hundreds of ms) | Longer pause |
| Full GC | Young + Old + Metaspace | Slowest | Worst-case pause |
You want most collections to be Minor. Frequent Full GCs are a red flag — usually means the old generation is too small or you’re leaking memory.
4. Stop-the-world pauses
Most GCs freeze every application thread for part of their work. That’s a stop-the-world (STW) pause.
- During STW, no requests are processed.
- Latency-sensitive apps (trading, real-time) care a lot about pause length.
- Modern collectors (G1, ZGC, Shenandoah) shrink STW down to milliseconds.
5. The GC algorithms
The four collectors that come up in interviews:
Serial GC
- One thread does all the work, app threads freeze.
- For single-core / tiny heap apps (think CLI tools, small containers).
- Flag:
-XX:+UseSerialGC.
Parallel GC (a.k.a. Throughput collector)
- Multiple threads do the GC work in parallel — still stop-the-world, but faster.
- Optimised for throughput, not latency.
- Was the default until Java 8.
- Flag:
-XX:+UseParallelGC.
G1 GC (Garbage First)
- Divides the heap into many small regions instead of fixed young/old areas.
- Tries to hit a pause-time target (e.g. 200 ms) by collecting only the regions with the most garbage first.
- Default since Java 9. Good general-purpose choice.
- Flag:
-XX:+UseG1GC(already on by default in modern JDKs).
ZGC
- Low-latency collector designed for sub-millisecond pauses, even with multi-terabyte heaps.
- Does most work concurrently with the app.
- Use for latency-sensitive services on large heaps.
- Flag:
-XX:+UseZGC. Production-ready from Java 15.
| Collector | Best for | Pause |
|---|---|---|
| Serial | Tiny apps, single core | Long |
| Parallel | Throughput-heavy batch jobs | Medium |
| G1 (default) | Most server apps | ~200 ms target |
| ZGC | Latency-critical, big heaps | <1 ms |
Shenandoah (Red Hat) is similar to ZGC and also worth knowing by name.
Older “CMS” (Concurrent Mark Sweep) is deprecated since Java 9 and removed in Java 14. Mention it only if asked about legacy systems.
6. Tuning basics
You don’t need to know every flag. The ones interviewers actually ask about:
| Flag | Meaning |
|---|---|
-Xms512m |
Initial heap size |
-Xmx2g |
Maximum heap size |
-XX:MaxRAMPercentage=75 |
Use 75% of the container’s memory (better than -Xmx in Docker/K8s) |
-XX:+UseG1GC |
Pick G1 |
-XX:MaxGCPauseMillis=200 |
G1 pause-time target |
-Xlog:gc*:file=gc.log |
GC logging (replaces older -XX:+PrintGCDetails) |
-XX:+HeapDumpOnOutOfMemoryError |
Dump heap when OOM happens — helps debug leaks |
Rule of thumb: start with defaults (G1) and MaxRAMPercentage. Tune only after measuring with GC logs.
7. Common interview questions
Q: Can you force the garbage collector to run?
A: You can suggest it with System.gc(), but the JVM is free to ignore it. Don’t rely on it in production code.
Q: What is the difference between Minor GC and Full GC? A: Minor GC collects only the young generation — fast, frequent, short pause. Full GC collects young + old + metaspace — slow and rare. Frequent Full GCs usually mean a memory leak or wrongly sized old generation.
Q: What is stop-the-world? A: A pause where the GC freezes all application threads to do its work. Modern collectors like G1 and ZGC shrink this to a few milliseconds.
Q: Which GC is the default in modern Java? A: G1 since Java 9. ZGC for low-latency apps with large heaps.
Q: What is a memory leak in Java?
A: Objects you don’t need any more are still reachable from a GC root, so the GC can’t collect them. Common causes: static collections that keep growing, listeners not unregistered, ThreadLocal not cleaned up.
Q: What replaced PermGen in Java 8?
A: Metaspace, which lives in native memory (not the heap). PermGen had a fixed size and caused OutOfMemoryError: PermGen space; Metaspace grows as needed (you can cap it with -XX:MaxMetaspaceSize).
Q: What’s the difference between heap and stack memory?
A: Stack holds method frames and local variables; one stack per thread; small (~256 KB–1 MB), freed when methods return. Heap holds all objects (new allocations); shared across threads; managed by the GC.
Q: What is a strong / soft / weak / phantom reference? A:
- Strong — normal reference. Object lives as long as a strong ref exists.
- Soft — collected only if the JVM needs memory. Used for caches.
- Weak — collected at the next GC. Used in
WeakHashMap. - Phantom — never returns the object; used to track when GC has finalised it.
Q: How would you diagnose a memory leak in production?
A: Enable GC logs, take a heap dump (jmap -dump or -XX:+HeapDumpOnOutOfMemoryError), open it in Eclipse MAT or VisualVM, look at the dominator tree for big retained objects.
8. Summary
| Concept | One line |
|---|---|
| Garbage | Unreachable objects on the heap |
| Generations | Young (Eden + Survivors) + Old + Metaspace |
| Minor GC | Cleans young — fast, frequent |
| Full GC | Cleans everything — slow, rare |
| STW | App pauses while GC runs |
| Default | G1 since Java 9 |
| Low latency | ZGC for sub-millisecond pauses |
| Tuning | Start with MaxRAMPercentage + GC logs |
Next steps
- Data structures — what lives on the heap
- Multithreading — threads, stack memory, virtual threads
- Production readiness — JVM flags in containers
Happy Learning
Practice checkpoint
-
Object A references B, B references A, nothing else references either — collected? Answer: yes — cycle unreachable from GC roots is garbage.
-
Minor GC vs Full GC — which is usually cheaper? Answer: Minor GC (young generation only).
-
Long-lived cache grows old gen until Full GC thrashing — likely fix direction? Answer: cap/evict cache, increase heap if legitimate, or fix leak; tune collector second.
-
What is a GC root? Answer: starting points: thread stack locals, static fields, JNI refs, etc.
Interview angles
- Reachability vs reference counting: JVM uses tracing; reference counting alone fails on cycles.
- Stop-the-world: most collectors pause app threads briefly; ZGC/Shenandoah target low ms pauses.
- Generational hypothesis: most objects die young → Eden collection is hot path.
- Leak definition: reachable but unused — static map holding everything is classic leak pattern.