Object-Oriented Programming Basics

Object Lifecycle & Garbage Collection

15 min Lesson 7 of 14

Object Lifecycle & Garbage Collection

Every object in Java is born, lives in memory for a while, and eventually dies. Unlike languages such as C or C++, you never have to manually free memory in Java — the garbage collector (GC) handles that automatically. Understanding when and why an object is removed helps you write code that is both correct and memory-efficient.

Step 1 — Object Creation

An object is created with the new keyword. Java does two things at that moment: it allocates a chunk of memory on the heap to hold the object's fields, and it runs the constructor to initialise those fields.

public class Dog { String name; int age; Dog(String name, int age) { this.name = name; this.age = age; } } // In main: Dog rex = new Dog("Rex", 3); // object created on the heap

After this line, rex is a reference variable. It does not contain the object itself — it contains the memory address where the object lives. Think of it as a remote control: the remote is the variable, the TV is the object on the heap.

Step 2 — References Keep Objects Alive

An object stays alive as long as at least one reference points to it. You can have multiple references to the same object:

Dog rex = new Dog("Rex", 3); Dog also = rex; // both variables point to the SAME object also.age = 4; // changes the shared object System.out.println(rex.age); // prints 4, not 3
References vs. copies. Assigning one object variable to another does not copy the object — it copies the reference. Both variables now point to the same heap memory. This is a very common source of bugs for beginners.

Step 3 — Becoming Eligible for Garbage Collection

An object becomes eligible for garbage collection (eligible for GC) the moment no reachable reference points to it anymore. There are several ways this happens:

  1. The variable goes out of scope. Local variables are destroyed when the method they belong to returns.
  2. You reassign the variable. The old object loses the reference.
  3. You set the variable to null. Explicitly removes the reference.
// 1. Out of scope void createTemp() { Dog temp = new Dog("Buddy", 1); // temp goes out of scope when the method returns // the Dog object is now eligible for GC } // 2. Reassignment Dog a = new Dog("Luna", 2); a = new Dog("Max", 5); // the "Luna" object has no reference — eligible for GC // 3. Null assignment Dog b = new Dog("Bella", 4); b = null; // "Bella" object is now eligible for GC
Set large objects to null when you are done with them if they are stored in long-lived variables (such as static fields or instance fields of a long-running object). It is not needed for local variables because they disappear when the method returns anyway.

Step 4 — The Garbage Collector Runs

Being eligible for GC does not mean the object is freed immediately. The JVM's garbage collector runs on its own schedule — typically when heap memory runs low. It traces all reachable objects from a set of root references (local variables in running threads, static fields) and reclaims everything it cannot reach.

You can suggest that the GC run with System.gc(), but the JVM is free to ignore that hint. Never rely on it.

Do not write code that depends on when GC runs. The exact moment an object is freed is non-deterministic. If your class holds a resource (like an open file or a database connection), do not rely on GC to close it — close it explicitly, ideally with a try-with-resources block.

Island of Isolation

Objects can make each other ineligible for GC even when no external code can reach them. This is called an island of isolation. The JVM's GC handles this correctly by using reachability from root references, not just reference counts.

class Node { Node next; } Node a = new Node(); Node b = new Node(); a.next = b; b.next = a; // a and b point to each other a = null; b = null; // now BOTH are eligible for GC // even though they still reference each other

The Object Lifecycle — Summary

  • Created: new allocates heap memory and runs the constructor.
  • In use: at least one reachable reference keeps it alive.
  • Eligible for GC: no reachable reference exists.
  • Reclaimed: GC frees the memory at a time it chooses.
No manual free() in Java. Java was designed so developers focus on business logic, not memory management. The GC is sophisticated — modern collectors (G1, ZGC, Shenandoah) can reclaim memory with very short pauses even in large applications.

Practical Takeaway

For most everyday Java code you do not need to think about GC at all. Just let objects go out of scope naturally. The cases where it matters are: very large objects held in long-lived variables, cached collections that grow without bound, or classes that wrap native resources. In those cases, release references explicitly and use try-with-resources for anything closeable.