Master Core Java Programming From Scratch

Clear, interactive, and structured coding lessons designed for absolute beginners.

Garbage Collection in Java

Learn how the JVM automatically identifies unreachable objects and reclaims heap memory.

What is Garbage Collection?

Garbage Collection, commonly called GC, is the JVM's automatic memory-management mechanism for reclaiming heap memory occupied by objects that are no longer reachable.

Developers normally do not explicitly free Java objects. Instead, the garbage collector determines which objects are no longer reachable and may reclaim their memory.

Why Does Java Need Garbage Collection?

In languages with manual memory management, developers often need to explicitly release dynamically allocated memory. Java instead provides automatic memory management through the JVM.

Main benefit: Garbage collection reduces the amount of manual memory management required by application developers.

Object Reachability

Garbage collection is based primarily on reachability. An object is generally considered eligible for collection when it can no longer be reached through references from GC roots.

Java
Student student = new Student();

student.name = "Samadhan";

student = null;

After student is assigned null, the previously created object may become unreachable if there are no other references to it.

GC Roots

The garbage collector determines reachability starting from special references known as GC roots.

GC Root Category Example
Local variables References held by active stack frames.
Active threads Objects referenced by currently running threads.
Static references Objects reachable through active class-level references.
JNI references References maintained through native code.

Eligible for Garbage Collection

An object becomes eligible for garbage collection when there are no active references pointing to it. The JVM can then reclaim the memory occupied by that object when garbage collection occurs.

Garbage Collection Example

Java
class Demo {

    @Override
    protected void finalize() throws Throwable {

        System.out.println("Garbage Collector executed successfully at CIIT Institute 🤓❤️...!");

        System.out.println("Object is successfully 🫥 removed from Heap Memory...!");
    }
}

public class Main {

    public static void main(String[] args) {

        Demo object = new Demo();

        object = null;

        System.gc();

        System.out.println("Main method execution finished.");
    }
}

Output

Output
Main method execution finished.

Possible Garbage Collection messages:

Garbage Collector executed successfully at CIIT Institute 🤓❤️...!

Object is successfully 🫥 removed from Heap Memory...!

Line-by-Line Explanation

Code Explanation
class Demo Defines a class named Demo. An object of this class is created inside the main() method.
@Override Indicates that the finalize() method overrides the method inherited from Java's Object class.
protected void finalize() throws Throwable Defines the finalize() method. Older Java programs used this method for cleanup associated with garbage collection.
System.out.println("Garbage Collector executed successfully at CIIT Institute!"); Prints a message when the finalize() method executes.
System.out.println("Object is successfully removed from Heap Memory."); Prints a message describing the processing of the object for memory reclamation.
public class Main Defines the Main class that contains the entry point of the Java program.
public static void main(String[] args) This is the main method. Java starts program execution from this method.
Demo object = new Demo(); Creates a new Demo object. Memory for the object is allocated in the heap, and object stores its reference.
object = null; Removes the reference from the object variable. If there are no other references to the object, it becomes eligible for garbage collection.
System.gc(); Requests the JVM to consider performing garbage collection. It does not guarantee that garbage collection will happen immediately.
System.out.println("Main method execution finished."); Prints a message indicating that the main method has reached this point of execution.

How This Program Works

Flow
Step 1:
Demo object = new Demo();
        ↓
Object is created in Heap Memory

Step 2:
object = null;
        ↓
Reference to the object is removed

Step 3:
Object has no active reference
        ↓
Object becomes eligible for Garbage Collection

Step 4:
System.gc();
        ↓
JVM receives a request to perform Garbage Collection

Step 5:
Garbage Collector may process the object
        ↓
Memory may be reclaimed
Important:

System.gc() only requests garbage collection. The JVM decides whether and when garbage collection actually occurs. The finalize() mechanism is deprecated in modern Java and should not be used for normal resource cleanup.

Eligible Does Not Mean Immediately Collected

Making an object unreachable does not mean that the garbage collector immediately removes it.

The JVM decides when and how garbage collection occurs based on the selected garbage collector, runtime conditions, memory pressure, and other implementation details.

Important: Do not write application logic that depends on garbage collection happening at a particular moment.

Basic Garbage Collection Process

Concept
Objects allocated
        ↓
Objects become reachable
        ↓
References may disappear
        ↓
Unreachable objects identified
        ↓
Garbage collector reclaims memory

Mark-and-Sweep Concept

A simplified model of garbage collection is the mark-and-sweep approach.

  1. Start from GC roots.
  2. Mark objects that are reachable.
  3. Identify objects that are not marked.
  4. Reclaim memory associated with unreachable objects.
This is a conceptual model. Modern JVM garbage collectors use more sophisticated algorithms and optimizations.

Generational Garbage Collection

Many JVM garbage-collection designs take advantage of the observation that many objects become unreachable shortly after they are created, while some objects survive for a longer time.

Concept
Heap

Young Generation
    ↓
Short-lived objects

Objects that survive
    ↓

Older Generation
    ↓
Longer-lived objects

Young Generation

Newly created objects commonly begin their lifetime in the young generation in JVM garbage collectors that use a generational design.

Objects that survive collection cycles can be promoted to older regions.

Old Generation

Objects that remain reachable for longer periods may be promoted into older regions of the heap.

Collection behavior differs between garbage collectors, so applications should not rely on a particular internal heap layout.

Minor, Major, and Full GC Terminology

Terms such as minor GC, major GC, and full GC are commonly used when discussing JVM garbage collection. Their exact meaning can depend on the garbage collector and JVM version.

Term General Meaning
Minor GC Often refers to collection activity focused on young-generation regions.
Major GC A commonly used term for collection involving older regions, although terminology varies.
Full GC Generally refers to collection involving broader parts of the heap and potentially other memory-management work.

Garbage Collectors

The JVM provides different garbage collectors optimized for different workload characteristics.

Collector General Focus
Serial GC Simple collector that uses a single thread for GC work.
Parallel GC Designed to use multiple threads for collection and emphasizes throughput.
G1 GC Region-based collector designed to balance throughput and pause-time goals.
ZGC Low-latency collector designed for very short pause times on large heaps.
Shenandoah Collector designed to reduce pause times by performing more work concurrently.

Stop-the-World Pauses

Some garbage-collection operations require application threads to pause temporarily. Such pauses are commonly described as stop-the-world pauses.

Modern low-latency collectors perform much of their work concurrently to reduce the duration of application pauses.

System.gc()

Java
System.gc();

This method requests that the JVM consider performing garbage collection. It does not guarantee that garbage collection will happen immediately.

Best Practice: Avoid using System.gc() as a normal strategy for managing application memory.

Finalization

Older Java code sometimes used the finalize() mechanism for cleanup.

Finalization has been deprecated and should not be used as a modern resource-management technique.

For resources such as files, sockets, and database connections, use explicit resource-management mechanisms such as try-with-resources.

Resource Management with try-with-resources

Java
try (BufferedReader reader =
         new BufferedReader(new FileReader("data.txt"))) {

    String line = reader.readLine();

    System.out.println(line);

}

Garbage collection manages memory, but resources such as files should be closed explicitly through appropriate resource-management APIs.

Garbage Collection Does Not Prevent Memory Leaks

Java applications can still experience memory leaks when unnecessary objects remain reachable.

Java
class Cache {

    static List<Object> values = new ArrayList<>();

    static void add(Object value) {

        values.add(value);

    }

}

Objects stored in the static collection remain reachable through the collection. If the collection grows without limits, memory usage can grow continuously.

Weak References

Java provides reference types such as WeakReference for use cases where an object should not be kept strongly reachable solely by that reference.

Java
WeakReference<Student> reference =
    new WeakReference<>(new Student());

Student student = reference.get();

Weak references are useful in specialized memory-sensitive designs such as certain caches.

Monitoring Garbage Collection

When diagnosing memory or GC problems, developers can use JVM monitoring and profiling tools.

  • Java Flight Recorder.
  • Java Mission Control.
  • JVM garbage-collection logs.
  • Heap dumps and memory analyzers.
  • Application Performance Monitoring tools.

Garbage Collection Best Practices

  • Avoid unnecessary object creation.
  • Avoid retaining objects longer than required.
  • Avoid unbounded static collections and caches.
  • Use try-with-resources for closeable resources.
  • Do not depend on System.gc() for normal memory management.
  • Profile the application before changing JVM memory settings.

Interview Questions

Garbage collection is the JVM mechanism that automatically reclaims heap memory from objects that are no longer reachable.

No. It only requests that the JVM consider performing garbage collection.

Yes. Objects can remain reachable even when the application no longer logically needs them.

No. External resources should be managed using appropriate APIs such as try-with-resources.
Summary

Java uses automatic garbage collection to reclaim heap memory from unreachable objects. Understanding reachability, GC roots, heap behavior, collector choices, memory leaks, and explicit resource management is important for building reliable Java applications.