Java Garbage Collector Reachable and Unreachable Objects

0

When a Java program is executed, it create a thread called ‘Main’. The program itself can create additional threads . Each of the threads execute a set of methods, the first being the main() method. Java Runtime creates stack memory for each thread execution. Each stack frame contain the arguments or local variables that are references to objects.  Objects are created by Java’s “new” operator, and memory for new objects is allocated on the heap at run time.

Garbage collection is the process of automatically freeing objects that are no longer referenced by the program. Garbage collectors somehow keeps track of the graph of references starting with the root nodes. In this article, we will see thru an example a set of reachable and unreachable objects.

A bit about garbage collector

The garbage collector somehow determines all the objects that are no longer referred to by the program. After figuring out the unrecahable objects, it runs the ‘finalizer’ for the object if any and then frees the heap space occupied by such unreferenced objects. Since it is not possible to predict exactly when unreferenced objects will be garbage collected, it is not possible to predict when object finalizers will be run which is why Java programmer shouldn’t be depending on finalizer block to cleanup the dependent resources.

All the objects reachable from the root node are marked in some way, the unmarked objects are then garbage collected. The unmarked objects without finalizers may be freed immediately unless referred to by an unmarked finalizable object. All objects referred to by a finalizable object must remain on the heap until after the object has been finalized.

Root Set of References

Garbage detection is accomplished by defining a set of roots that are always accessible to the program. An object is reachable if there exists a path of reference from the roots by which the executing program can access the object. All the objects reachable from the roots are considered live. Any objects referred to by a live object are also considered live. Objects known to be unreachable are eligible for garbage collection. If any of the unreachable objects have finalizers, they must be finalized before they are freed.

Reachable and Unreachable Objects

In the below example, we have objects A and B directly reachable from the root. B in turn refers E so E is also reachable.  Object C is also created in the main program but later nullified. C refers to B and D but since C is unreachable after nullifying, D too becomes unreachable. Object F is created which in turn creates G an H. After nullifying F, all three objects become unreachable.

Object Tree

Object Tree

If you observe from the above diagram, object C refers to object B which is reachable from the root but C itself is an unreachable object. Likewise, object D, F, G and H are unreachable in spite of references to it because those references are all coming from unreachable objects.

GarbageCollectionExample:

package com.javarticles.references;


public class GarbageCollectionExample {
    public static void main(String[] args) {
        B b = new B();
        A a = new A(b);
        C c = new C(b);
        c = null;
        F f = new F();
        f = null;
        
        System.out.println("Keep creating objects in heap, this should throw OutOfMemoryError");
        boolean gcRun = false;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i <10000000; i++) {
            try {
                sb.append("one").append(sb.toString());
            } catch (java.lang.OutOfMemoryError e) {
                System.out.println("This should run the gc");
                gcRun = true;
                break;
            }
        }
        if (!gcRun) {
            System.out.println("In case Gc didnt run, run now");
            Runtime.getRuntime().gc();
        }
    }
  
}

A:

package com.javarticles.gc;

public class A {
    private B b;
    
    public A(B b) {
        this.b = b;
    }
    
    @Override
    public void finalize() {
        System.out.println("A cleaned");
    }
}

B:

package com.javarticles.gc;

public class B {
    private E e = new E();

    @Override
    public void finalize() {
        System.out.println("B cleaned");
    }
}

C:

package com.javarticles.gc;

public class C {
    private B b;
    private D d = new D();

    public C(B b) {
        this.b = b;
    }

    @Override
    public void finalize() {
        System.out.println("C cleaned");
    }
}

D:

package com.javarticles.gc;

public class D {
    @Override
    public void finalize() {
        System.out.println("D cleaned");
    }
}

E:

package com.javarticles.gc;

public class E {
    @Override
    public void finalize() {
        System.out.println("E cleaned");
    }
}

F:

package com.javarticles.gc;

public class F {
    private G g = new G(this);
    @Override
    public void finalize() {
        System.out.println("F cleaned");
    }
}

G:

package com.javarticles.gc;

public class G {
    private H h;
    public G(F f) {
        h = new H(f);
    }
    @Override
    public void finalize() {
        System.out.println("G cleaned");
    }
}

H:

package com.javarticles.gc;

public class H {
    private F f;

    public H(F f) {
        this.f = f;
    }
    @Override
    public void finalize() {
        System.out.println("H cleaned");
    }
}

Output

Keep creating objects in heap, this should throw OutOfMemoryError
H cleaned
G cleaned
C cleaned
F cleaned
D cleaned
This should run the gc

Download the source code

This article was about Garbage Collector, its set of root references and definition of reachable and unreachable object.

You can download the source code here: javagcunreachableobjectsexample.zip

About Author

Ram’s expertise lies in test driven development and re-factoring. He is passionate about open source technologies and loves blogging on various java and open-source technologies like spring.
You can reach him at [email protected]

Comments are closed.