Garbage Collection in Java
Garbage collection (GC) in Java is the automatic process of finding objects that the program can no longer reach and freeing their memory. In languages such as C, programmers must free memory themselves, which leads to crashes when memory is freed too early and leaks when it's forgotten. In Java, the garbage collector does this work for you, running alongside your program. In this lesson, you will learn what garbage collection does, what it costs, and how to watch it from a program.
What the Garbage Collector Does
- Finds live objects by following references from GC roots (see "Object Lifecycle and Reachability").
- Reclaims the memory of everything else.
- Compacts memory (in most collectors) by moving live objects together, so new objects can be allocated quickly in one free block.
Benefits and Costs
| Benefits | Costs |
|---|---|
No manual free or delete | Uses CPU time |
| No dangling-pointer crashes | Some phases pause the application ("stop-the-world") |
| Most leaks of forgotten memory are prevented | Needs extra memory to work efficiently |
| Very fast allocation (bump a pointer) | Timing of collection isn't under your control |
Example: Counting Garbage Collections
Let's see an example that creates lots of short-lived garbage and asks the JVM how many collections happened.
import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
public class GcCount {
static long totalCollections() {
long count = 0;
for (GarbageCollectorMXBean gc :
ManagementFactory.getGarbageCollectorMXBeans()) {
count += Math.max(0, gc.getCollectionCount());
}
return count;
}
public static void main(String[] args) {
long before = totalCollections();
long checksum = 0;
for (int i = 0; i < 200_000; i++) {
String report = "Report " + i + " for Navika";
byte[] buffer = new byte[10_000];
checksum += report.length() + buffer.length;
}
long after = totalCollections();
System.out.println("Checksum: " + checksum);
System.out.println("Garbage collections happened? " + (after > before));
for (GarbageCollectorMXBean gc :
ManagementFactory.getGarbageCollectorMXBeans()) {
System.out.println("Collector: " + gc.getName());
}
}
}Checksum: 2004688890
Garbage collections happened? true
Collector: G1 Young Generation
Collector: G1 Concurrent GC
Collector: G1 Old GenerationExplanation: Each loop iteration creates a string and a 10 KB array that are garbage as soon as the iteration ends: about 2 GB of garbage in total, far more than the heap. The garbage collector ran many times to reclaim it, so the program never ran out of memory. The default collector in Java 25 is G1, which reports separate young, concurrent and old collections.
Short-Lived Objects Are Cheap
Common Mistakes
Calling System.gc() to "clean up". It usually makes performance worse; let the JVM decide.
Thinking GC prevents all memory leaks. Objects you still reference can't be collected.
Using finalize() for cleanup. It's deprecated for removal; use try-with-resources or Cleaner.
Interview Corner
What is garbage collection in Java?
Garbage collection is the JVM's automatic memory management: the garbage collector identifies objects that are no longer reachable from GC roots (live thread stacks, static fields, JNI references and so on) and reclaims their memory, usually also compacting the heap. It removes manual deallocation errors such as double frees and dangling pointers, at the cost of CPU time, extra memory and pauses whose length depends on the collector. Java 25's default collector is G1.
Practice
- Easy: Print the name of each garbage collector in your JVM with
ManagementFactory.getGarbageCollectorMXBeans(). - Harder: Print each collector's total collection time with
getCollectionTime()after a loop that creates garbage, and compare runs with-Xmx32mand-Xmx512m.
Key Takeaways
Was this tutorial helpful?