Nearby lessons

104 of 125

Java - Garbage Collection

📌 What You Will Learn
  • What garbage collection is and why Java needs it
  • When an object becomes eligible for collection
  • How to request garbage collection: System.gc()
  • finalize() vs the modern Cleaner
  • The Generational idea (new vs old memory)

Garbage Collection is a core concept of the Java language. This lesson explains The Problem Garbage Collection Solves, When Does an Object Become Garbage? and Interesting Case — Circular References with complete, runnable code examples, clear step-by-step explanations, and common mistakes to avoid with exam-style MCQs at the end.

The Problem Garbage Collection Solves

In languages like C/C++, the programmer must manually free memory after use (free in C, delete in C++). If you forget, the program slowly eats memory and crashes — this is called a memory leak.

Java removes this headache with the Garbage Collector (GC) — an automatic process that finds unused objects and frees their memory while the program runs. You never have to free memory yourself.

Think of the GC as a housekeeping staff: whenever you leave an object no longer needed, the GC quietly throws it out and clears the space. That is why Java is called a robust and developer-friendly language.

In simple words: The Garbage Collector frees the memory of objects that no one uses anymore. You never write free or delete — the JVM spots unreachable objects by itself and clears them in the background.

When Does an Object Become Garbage?

An object becomes eligible for garbage collection when no reference points to it anymore — in other words, nothing can ever use it again. This happens in two common ways:

In simple words: An object becomes garbage the moment no reference can reach it. Setting a reference to null, repointing it, or letting the method that created it finish all make the old object eligible for collection.
Example02
JCode Cell
1class Student { String name; }
2 
3class GcDemo {
4 public static void main(String[] args) {
5 // Way 1: assign null
6 Student s1 = new Student();
7 s1 = null; // object is now unreachable -> garbage
8 
9 // Way 2: point to another object
10 Student s2 = new Student();
11 Student s3 = new Student();
12 s2 = s3; // old s2 object is now unreachable -> garbage
13 
14 // Way 3: object created inside a method dies when method ends
15 makeStudent(); // its local object becomes garbage here
16 }
17 
18 static void makeStudent() {
19 Student temp = new Student(); // dies when this method returns
20 }
21}

Interesting Case — Circular References

Here is a subtle point: if objects refer to each other in a cycle but nothing outside refers to them, they are still garbage. The GC understands that the whole cycle is unreachable.

Example03
JCode Cell
1class Node {
2 Node next;
3}
4 
5// A <-> B (both point to each other, nothing else points to them)
6Node a = new Node();
7Node b = new Node();
8a.next = b;
9b.next = a;
10a = null;
11b = null; // now both are garbage (cycle is unreachable)

How to Request Garbage Collection

You cannot force the GC to run instantly — it decides when to run. But you can request it politely with:

Trainer's Note: System.gc() is a request, not a command. The JVM may ignore it if it thinks memory is fine. In real applications, calling System.gc() often is bad practice — it slows the app. Trust the GC to do its job.
Example04
JCode Cell
1System.gc(); // request (not command) the GC to run
2Runtime.getRuntime().gc(); // the same thing in Runtime form

finalize() vs the Modern Cleaner

Older Java had finalize() — a method the GC called just before destroying an object, letting you clean up resources. But finalize() was unreliable and slow.

Updated knowledge: finalize() is deprecated (since Java 9) and removed (Java 18). The modern replacement is the Cleaner mechanism (Java 9+) or simply try-with-resources. Use these instead:

Example05
JCode Cell
1// OLD (Java 1-8): finalize
2class OldClass {
3 protected void finalize() {
4 System.out.println("Object is being collected");
5 }
6}

finalize() vs the Modern Cleaner

In simple words: `finalize()` is old and unreliable — use try-with-resources or `Cleaner` instead. For files and database connections, try-with-resources closes them automatically and at the right time.
Example06
JCode Cell
1// MODERN: use try-with-resources for files, DB connections, etc.
2try (Connection con = getConnection()) {
3 // work with con - it closes automatically
4}
5 
6// or the Cleaner utility for special resources (advanced)
7Cleaner cleaner = Cleaner.create();
8cleaner.register(obj, () -> System.out.println("cleaning up..."));

Memory and the Heap

Objects live in the heap — a big shared memory area. We can peek at memory usage using the Runtime class:

Example07
JCode Cell
1class RuntimeDemo {
2 public static void main(String[] args) {
3 Runtime r = Runtime.getRuntime();
4 System.out.println("Total memory: " + r.totalMemory());
5 System.out.println("Free memory: " + r.freeMemory());
6 }
7}

The Generational Idea (How Modern GC Works)

Modern JVMs use a smart trick called generational collection. Most objects die young, so memory is split into areas:

AreaWhat lives thereWhy
Young GenerationNewly created objectsMost objects die here quickly — collecting here is cheap and frequent.
Old GenerationObjects that survived many collectionsLong-lived objects move here; collected rarely.
(Meta/Method area)Class definitions and static dataNot part of normal object GC.
In simple words: Most objects die young, so the JVM separates new memory from old memory. Newly created objects stay in the young generation, where collection is cheap and frequent; survivors move to the old generation and are collected rarely.

GC collectors you will hear about: Serial (simple, single-thread), G1 (Garbage First) — the default since Java 9, good for big heaps, and ZGC — for huge heaps with very low pauses (Java 15+).

📝 Key Takeaways
  • Garbage Collection automatically frees memory of unused objects.
  • An object becomes garbage when no reference reaches it (null, reassignment, method end, unreachable cycle).
  • System.gc() is only a request — the JVM decides when to collect.
  • finalize() is deprecated/removed; use try-with-resources or Cleaner instead.
  • Objects live in the heap; modern GC uses Young and Old generations.
  • G1 is the default GC; ZGC is for huge heaps with tiny pauses.

🧠 Test Your Knowledge

8 Questions
Progress: 0 / 8