Java · OOP, JVM and backend craft
How does garbage collection work in the JVM?
Short answer
The JVM reclaims unreachable objects by tracing from GC roots. Modern collectors are generational and mostly concurrent, trading throughput and memory for shorter pauses.
Garbage collection starts from roots such as thread stacks, static fields, JNI references and active class loaders. Anything reachable from those roots is live. Everything else can be reclaimed. Reference counting alone cannot handle cycles, so the JVM uses tracing.
Generational collection
- The young generation holds new objects in Eden plus two survivor spaces
- Minor collections copy live young objects between survivor spaces and promote long-lived ones
- The old generation holds promoted objects and is collected less frequently
- Most objects die young, so collecting the young generation frequently is efficient
G1 is the default collector on modern JDKs. It divides the heap into regions and targets a pause-time goal. ZGC and Shenandoah pursue very low pauses by doing most work concurrently. Serial and Parallel are still useful for small heaps or throughput-focused batch jobs.
List<byte[]> cache = new ArrayList<>();
for (int i = 0; i < 10_000; i++) {
cache.add(new byte[1024]);
}
cache.clear();Tuning starts with measurement, not guesswork. Enable GC logging, inspect pause distribution and allocation rate, then adjust heap size, collector choice or object lifetime. A larger heap can reduce collection frequency but increases worst-case pause and memory cost.
Follow-ups you should expect
Interviewers use these to check whether the first answer was understanding or memorisation.
- 1What are GC roots?
- 2Why are objects promoted to the old generation?
- 3When would you choose ZGC over G1?
- 4How do you investigate a memory leak in a long-running service?
Say it in the interview
The JVM traces reachable objects from roots such as thread stacks and static fields, and unreachable objects become eligible for collection. Modern collectors are generational because most objects die young, so young collections are cheap and frequent. G1 is the usual default, while ZGC and Shenandoah target very short pauses. I tune with GC logs and allocation data, not by guessing flags, and I treat explicit collection calls as a code smell.
Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.
Related questions
Reading is step one
Now say it out loud.
Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live Java mock interview and get scored feedback on depth, clarity and confidence.