Header Ads Widget

Responsive Advertisement

Garbage Collection Under Standing



Garbage Collection in Depth: Understanding

Introduction to Garbage Collection in Java

Garbage collection (GC) is the process of automatically identifying and reclaiming memory that is no longer in use by the program. Java provides this capability to manage memory automatically, so programmers don’t need to explicitly free up memory as they would in languages like java, C/C++. The goal of the garbage collector is to find and remove objects that are unreachable and no longer needed by the application, freeing up memory for future allocations.

Java uses several algorithms to perform garbage collection, like Mark-and-Sweep and Generational GC.

Ways an Object Becomes Eligible for Garbage Collection

Objects become eligible for garbage collection in several ways:

  1. Nullifying an Object Reference When an object is no longer needed, setting its reference to null will make it eligible for garbage collection if no other references to the object exist.

java

Student s1 = new Student();

Student s2 = new Student();

// Currently, no object is eligible for GC

 

s1 = null;  // Now the object referenced by s1 is eligible for GC

s2 = null;  // Now the object referenced by s2 is eligible for GC

 

Once s1 and s2 are set to null, the objects they reference are no longer reachable and are eligible for garbage collection.

  1. Reassigning a Reference If a reference variable that holds an object is reassigned to another object, the previously referenced object becomes eligible for garbage collection if no other reference exists.

java

Student s1 = new Student();

Student s2 = new Student();

// Currently, no object is eligible for GC

 

s1 = new Student();  // The original object referenced by s1 is now eligible for GC

s2 = s1;             // The original object referenced by s2 is now eligible for GC

 

Here, reassigning s1 to a new object makes the original object referenced by s1 eligible for garbage collection. When s2 = s1 happens, the old object that s2 was pointing to becomes eligible for garbage collection.

  1. Objects Created Inside a Method Any object created inside a method is eligible for garbage collection once the method finishes execution, provided there are no references to it outside the method.

i. Method Holds a Reference Variable
If a method holds a reference variable that is returned, the object will remain in memory until the returned reference is no longer in use:

java

public Student createStudent() {

    Student s = new Student();  // Local object reference

    return s;  // As long as the returned reference exists, the object isn't GC eligible

}

 

ii. Method Doesn’t Hold a Reference Variable If the method does not return a reference or store it elsewhere, the object will be eligible for garbage collection after the method completes:

java

public void createStudent() {

    Student s = new Student();  // Local reference

    // No return statement or global reference

}

// The object is eligible for GC once the method execution finishes

 

iii. Global Object Reference in Method If a method assigns an object to a global variable, it won't be garbage-collected until the global reference is reassigned or set to null:

java

Student globalStudent;

 

public void createGlobalStudent() {

    globalStudent = new Student();  // Global reference holds the object

}

// The object remains in memory as long as globalStudent references it

 

Island of Isolation

An island of isolation occurs when a group of objects reference each other but are otherwise unreachable from the root references (such as from the stack or static fields). Even though the objects are mutually referenced, they can still be garbage collected because no active parts of the application can reach them.

For example:

java

class Student {

    Student friend;

}

 

Student s1 = new Student();

Student s2 = new Student();

s1.friend = s2;

s2.friend = s1;

 

s1 = null;

s2 = null;  // Both s1 and s2 are now eligible for GC despite referencing each other

 

Here, s1 and s2 reference each other, but since they are no longer reachable from outside references, they form an "island of isolation" and are eligible for garbage collection.

Conclusion

Garbage collection in Java ensures that memory is managed automatically, and objects no longer in use are reclaimed. There are various ways objects become eligible for garbage collection:

  1. Nullifying references.
  2. Reassigning references.
  3. Method-scoped objects.
  4. Island of isolation where circular referencing occurs but no external access exists.

Key Notes:

  1. NB 1: When an object has no reference, it is eligible for garbage collection.
  2. NB 2: If an object has references but these references are isolated from external access (i.e., Island of Isolation), it is also eligible for garbage collection.

 

 

Island of Isolation
Island of Isolation



 

How to Call the Garbage Collector

There are two ways to explicitly suggest that the garbage collector runs:

Ø  Using the System class:

java

System.gc();  // Static method

 

Ø  Using the Runtime class:

java

Runtime.getRuntime().gc();  // Instance method

 

Difference Between System.gc() and Runtime.getRuntime().gc()

Ø  System.gc() is a static method of the System class. It internally calls Runtime.getRuntime().gc().

ü  Performance: Slower compared to direct Runtime.gc() call.

Ø  Runtime.getRuntime().gc() is an instance method of the Runtime class, and it directly triggers garbage collection.

ü  Performance: Better performance since it avoids the overhead of the System.gc() wrapper.

Finalization:

Ø  The finalize() method is called by the garbage collector before an object is destroyed, to allow for clean-up actions (like closing file streams).

Ø  Signature:

java

protected void finalize() throws Throwable {}

 

Case 1: Finalize Method Called by GC

When an object is no longer referenced and is eligible for GC, the finalize() method (if overridden) will be called once before destruction.

Example 1: Calling System.gc() on a String Object (No Custom Finalization):

Java

public class Test {

    public static void main(String[] args) {

        String t1 = new String();

        t1 = null;  // Object becomes eligible for GC

        System.gc();  // Suggest garbage collection for t1

        System.out.println("End of Main method");

    }

 

    public void finalize() {

        System.out.println("Kartik destroyed");

    }

}

 

Output:

End of Main method

 

Since t1 is a String object, and the finalize() method is not overridden for String, no custom message will be printed.

Example 2: Calling System.gc() on a Test Object (Custom Finalization):

java

public class Test {

    public static void main(String[] args) {

        Test t1 = new Test();

        t1 = null;  // Object becomes eligible for GC

        System.gc();  // Suggest garbage collection for t1

        System.out.println("End of Main method");

    }

 

    public void finalize() {

        System.out.println("Kartik destroyed");

    }

}

 

Possible Output 1:

End of Main method

Kartik destroyed

 

Possible Output 2:

Kartik destroyed

End of Main method

 

The order of output depends on the JVM and when it schedules garbage collection.

Case 2: Finalize Method Called Explicitly

You can explicitly call the finalize() method, but it won’t destroy the object. The GC will still invoke finalize() before destroying the object.

java

public class Test {

    public static void main(String[] args) {

        Test t1 = new Test();

        t1.finalize();  // Explicit call, acts like a normal method call

        t1 = null;  // Eligible for GC

        System.gc();  // GC may call finalize again

        System.out.println("End of Main method");

    }

 

    public void finalize() {

        System.out.println("Kartik destroyed");

    }

}

 

Output:

Kartik destroyed

End of Main method

 

In this case, finalize() is called twice: once explicitly and once by the garbage collector.

Case 3: Finalize Called Only Once by GC

Even if an object becomes eligible for GC multiple times, finalize() will only be called once by the garbage collector.

java

public class Test {

    static Test s;

 

    public static void main(String[] args) throws InterruptedException {

        Test t = new Test();

        System.out.println(t.hashCode());

        t = null;

        System.gc();  // Eligible for GC, first call to finalize()

        Thread.sleep(5000);

        System.out.println(s.hashCode());  // Resurrected in finalize()

        s = null;

        System.gc();  // Eligible for GC again, finalize won't be called again

        Thread.sleep(10000);

        System.out.println("End of Main method");

    }

 

    public void finalize() {

        System.out.println("Kartik destroyed");

        s = this;  // Resurrecting the object

    }

}

 

Output:

2346362

Kartik destroyed

2346362

End of Main method

 

The object is resurrected in the first finalize() call, preventing it from being collected. The second GC invocation doesn’t call finalize() again, as it is only called once per object.

Case 4: Garbage Collection Without Explicit System.gc() Call

Garbage collection can be triggered automatically by the JVM when it detects low memory conditions.

java

public class Test {

    static int count;

 

    public static void main(String[] args) {

        for (int i = 0; i < 1000000; i++) {

            Test t = new Test();

            t = null;  // Eligible for GC

        }

        System.out.println("End of Main method");

    }

 

    public void finalize() {

        count++;

        System.out.println("Kartik destroyed " + count);

    }

}

 

Output: Garbage collection will be triggered automatically by the JVM when memory is low, and each Test object will have finalize() called at least once, printing "Kartik destroyed".

Memory Leaks in Java

Memory leaks occur when objects are no longer needed but are not garbage-collected because they are still referenced somewhere in the program. Tools like HP-J-Meter, IBM-Tivoli, and J-Profiler can help detect memory leaks.

String vs. StringBuffer

Ø  String: Immutable; modifications create new objects.

java

String s = new String("Kartik");

s.concat("Mandal");  // Creates a new String, s still points to "Kartik"

System.out.println(s);  // Output: Kartik

 

Ø  StringBuffer: Mutable; modifications change the existing object.

java

StringBuffer sb = new StringBuffer("Kartik");

sb.append("Mandal");

System.out.println(sb);  // Output: KartikMandal

 

Conclusion

Garbage collection and memory management are automatic in Java, but understanding how objects become eligible for GC and how to work with finalize() can help avoid memory leaks and optimize resource management.

 

Post a Comment

0 Comments