Garbage Collection in Java

Garbage collection in Java is the process of automatically freeing heap memory by deleting unused objects that are no longer accessible in the program.

In other simple words, the process of automatic reclamation of runtime unused memory is known as garbage collection.

The program that performs garbage collection is called a garbage collector or simply a collector in Java. It is a part of the Java platform and is one of the major features of the Java Programming language.

Java garbage collector runs in the background in a low-priority thread and automatically cleans up heap memory by destroying unused objects.

However, before destroying unused objects, it makes sure that the running program in its current state will never use them again. This way, it ensures that the program has no reference variable that does not refer to any object.

Dead Object or Garbage in Java


An object that cannot be used in the future by the running program is known as garbage in Java. It is also known as dead object or unused object. For example, an object exists in the heap memory, and it can be accessed only through a variable that holds references to that object.

What should be done with a reference variable that is not pointing to any object? Such situations can happen in the program. Consider the following two statements below:

Hello h1 = new Hello();
Hello h2 = new Hello();
h1 = h2;

Here, we have assigned one reference variable h1 to another reference variable h2. After the assignment statement h1 = h2, h1 refers to the same object referenced by h2 because the reference variable h2 is copied to variable h1. Due to which the reference to the previous object is gone.

Garbage Collection in Java

Thus, the object previously referenced by h1 is no longer in use i.e. the object referred by the reference variable h1 that is left side to the assignment operator, is not referring to the previous object and therefore is known as garbage or dead object.

Since garbage occupies memory space, therefore, the Java runtime system (JVM) detects garbage and automatically reclaims the memory space it occupies. This process is called garbage collection in java. The garbage collector has the responsibility to keep track of which objects are “garbage.”

In C/C++ programming languages, the programmer has the responsibility for both creation and destroying of objects by using methods provided by C and C++ languages.

Generally, programmer ignores or forgets destroying of unused objects. Due to this carelessness, after a certain time, sufficient memory space is not available for creating new objects. As a result, the entire program will terminate abnormally causing OutOfMemoryErrors.

But in Java language, the programmer has no responsibility to keep the track of all those unused objects which are no longer in use. The garbage collector has the responsibility to destroy these unused objects to clean up the memory space. The best example of garbage collector is Daemon thread that is always running in the background.

So, the main objective of Garbage Collector in java is to free up heap memory by destroying unreachable objects that are not referenced by any reference variable. An object that can be used in the future by the running program is called live object in Java or a reachable object.

How is an Object Eligible for Garbage Collection in Java?


There are the following criteria by which JVM detects unused objects and the garbage becomes eligible for Java garbage collection. They are as follows:

1. When we explicitly assign null to the reference variable, the object pointed by that reference variable is not referred to or unused. Consider the following two statements below:

Student st = new Student("Ivaan Sagar");
   st = null;

In the first statement, a reference to a newly created Student object is stored in the reference variable st. But in the next statement, the value of st is changed, and the reference to the Student object is gone. In this situation, JVM will automatically detect unused object if an object is not referenced by any reference variable.

2. When we assign one reference variable to another reference variable, the object pointed by the reference variable left-side to the assignment operator is unused and it is eligible for garbage collection.

School sc1 = new School();
School sc2 = new School();
    sc1 = sc2;

3. When the reference variable is out of scope then the object referred by that reference variable is unused or referred and it is eligible for garbage collection.

Java runtime system (JVM) uses these techniques and identifies the unreachable (unused) object when JVM faces the memory shortage problem.

JVM calls garbage collection (GC) by handing over the list of unused objects. Hence, garbage collection is mainly responsible for cleaning memory of unused objects.

Sometimes, some unreachable objects may refuse by GC for cleaning up memory because these objects may hold references to some resources such as JDBC database connection, IO stream connection, printer connection, network connection, etc.

When we release these resources which are referred by some unused objects, we can clean the memory space by detecting those unused objects without any trouble.

Ways for Invoking Garbage Collector (GC)


When the unused object becomes eligible for garbage collection, garbage collector does not destroy them immediately. JVM runs garbage collector whenever it runs low in memory.

It tries its best to clean up the memory of all unused objects before it throws a java.lang.OutOfMemoryError error. Therefore, we can only request JVM to run garbage collector. But it has free to ignore the request.

There are two methods for requesting JVM to run garbage collector. They are as follows:

1. Using Runtime.getRuntime().gc() method:

Runtime class permits the program to interface with the JVM in which the program is running. By using its gc() method, we can request JVM to run Garbage Collector. Use the following source code for requesting JVM to run garbage collector.

// Get the Runtime object.
     Runtime rt = Runtime.getRuntime();
// Call the garbage collector.
      rt.gc();

We can also combine the above two statements into one statement like this:
// Get runtime object and call the garbage collector.
     Runtime.getRuntime().gc();

The gc() method of the java.lang.Runtime class may be used only to pass a request to the JVM so that it may run the garbage collector.


2. Using System.gc() method:

System class contains a convenience method named gc() for requesting JVM to run Garbage Collector. It is a static method that is equivalent to executing the Runtime.getRuntime().gc() statement.

We can also use the following code to run the garbage collector:

// Invoke the garbage collector
     System.gc();

The call to the gc() method of System class is also just a request to the JVM. The JVM is free to ignore the call. Thus, there is no guarantee that any one of the above two methods will definitely run Garbage Collector by JVM.


Let’s take a simple example program where we will use the System.gc() method. In this program, we will create 1,000 objects of the Object class in the createObjects() method.

The references of new objects are not stored. So, they are garbage. When we will call the System.gc() method, we will try to request to the JVM to reclaim the memory used by these objects. We will display the memory freed by the garbage collector on the console.

Example 1:

package garbageCollectorProgram;
public class InvokingGC {
public static void main(String[] args) 
{
    long m1, m2, m3;
 // Call getRuntime() method to get a runtime object.
    Runtime rt = Runtime.getRuntime();
    for(int i = 0; i < 3; i++)
    {
     // Get free memory.
	m1 = rt.freeMemory();
     // Call createObjects() method to create some objects.
	createObjects(500);
     // Get free memory
	m2 = rt.freeMemory();
     
     // Invoke garbage collection.
	System.gc();
     // Get free memory
	m3 = rt.freeMemory();
	System.out.println("m1 = " + m1 + ", m2 = " + m2 + ", m3 = " +m3 + "\nMemory freed by gc() =  " + (m3 - m2));
	System.out.println("-------------------------");
    }
  }
public static void createObjects(int count) 
{
   for(int i = 0; i < count; i++) 
   {
   // Do not store references of new objects, so they are immediately eligible for garbage collection.
      new Object();
  }	
 }
}
Output:
        m1 = 15800200, m2 = 15800200, m3 = 16062600
        Memory freed by gc() = 262400
        -------------------------
        m1 = 15970832, m2 = 15970832, m3 = 16062048
        Memory freed by gc() = 91216
        -------------------------
        m1 = 15970224, m2 = 15970224, m3 = 16062048
        Memory freed by gc() = 91824
        -------------------------

Note that you may have the possibility to get a different output when you will run this program.

In general, it is not advisable to call the garbage collector programmatically. Invoking arbitrarily the garbage collector may slow down the performance of the application.

The Java runtime (JVM) takes care of reclaiming unused object’s memory automatically. An OutOfMemoryError error in the program can be generated due to many reasons.

JVM makes all try to free up memory by calling the garbage collector before throwing the OutOfMemoryError error. Therefore, simply calling the garbage collector programmatically will not make this error go away.

To resolve this error, look at the following points:

1. Review your program code to make sure that you are not storing some object references that you will never use again. Set these references to null so that they could eligible for GC.

2. If you are storing a large number of objects in static variables, these objects will remain in memory until the class itself is unloaded.

Generally, objects stored in static variables take up memory space forever. Therefore, review your source code and try to avoid storing a large number of objects in static variables.

3. Examine your source code and make sure that you are not caching large amounts of data in objects. If you are caching, use weak references to cache a large amount of data in objects. Objects referenced by weak references are garbage collected before JVM throws an OutOfMemoryError error.

4. If none of the above solutions work for you, you may attempt to adjust the size of heap memory.

Example Program based on Object Eligible for Garbage Collection


1. Java program to demonstrate GC when we assign one reference variable to another reference variable.

Example 2:

package garbageCollectorProgram;
public class GCTest 
{
   String objRef;
   public GCTest(String objRef)
   {
      this.objRef = objRef;
   }
public static void main(String[] args) 
{
// Create objects of class GCTest by passing arguments to its constructor. 
   GCTest t1 = new GCTest("t1");
   GCTest t2 = new GCTest("t2");
   t1 = t2;
// Invoke garbage collection.
      System.gc();
}
@Override
/* Overriding finalize method to check whether object previously referenced by objRef is garbage collected or not. */
protected void finalize() throws Throwable 
{
    System.out.println("Object previously referenced by "+ this.objRef + " is successfully garbage collected.");
 }
}
Output:
       Object previously referenced by t1 is successfully garbage collected.

1. As you can observe that the previous object referenced by t1 is no longer useful and becomes garbage. Thus, it becomes eligible for garbage collection in Java.

2. The finalize() method of Object class has been overridden so that we could know the clean-up activities performed by Garbage collector just before destroying object. Once the execution of finalize() method is completed, Garbage Collector destroys that object.

We will discuss more detail of finalize() method in the next tutorial.


2. Java program to demonstrate GC when we assign null to object reference.

Example 3:

package garbageCollectorProgram;
public class GCTest 
{
   String objRef;
   public GCTest(String objRef)
   {
      this.objRef = objRef;
   }
public static void main(String[] args) 
{
    GCTest t1 = new GCTest("t1");
    t1 = null;
 // Invoke garbage collection.
    System.gc();
}
@Override
/* Overriding finalize method to check whether the object referenced by objRef is garbage collected or not. */
protected void finalize() throws Throwable 
{	
    System.out.println("Object referenced by "+ this.objRef + " is successfully garbage collected.");
 }
}
Output:
         Object referenced by t1 is successfully garbage collected.

As you can see in the output when the reference variable of an object is changed to NULL, it becomes unreachable and thus becomes eligible for garbage collection.


3. Java program to demonstrate GC when there is an anonymous object without any object reference.

Example 4:

package garbageCollectorProgram;
public class GCTest 
{
   String objRef;
   public GCTest(String objRef)
   {
      this.objRef = objRef;
   }
public static void main(String[] args) 
{
   new GCTest("t1"); // Anonymous object creation. 
// Invoking garbage collection.
   System.gc();
}
@Override
/* Overriding finalize method to check whether anonymous object is garbage collected or not. */
protected void finalize() throws Throwable 
{	
    System.out.println(this.objRef+" is successfully garbage collected.");
 }
}
Output:
      t1 is successfully garbage collected.

4. Java program to demonstrate how objects created inside a method becomes eligible for GC after method execution completion.

Example 5:

package garbageCollectorProgram;
public class GCTest {
static void m1()
{
// Object referenced by t1 inside method becomes unreachable when m1() removed.
   GCTest t1 = new GCTest(); 
   m2();
}
static void m2()
{
  // Object referenced by t2 inside method becomes unreachable when m2() removed.
     GCTest t2 = new GCTest(); 
}
public static void main(String[] args) 
{
    new GCTest(); // Anonymous object creation. 
 // Invoking garbage collection.
     System.gc();
}
@Override
protected void finalize() throws Throwable 
{	
    System.out.println("Objects are successfully garbage collected.");
 }
}
Output:
          Objects are successfully garbage collected.

In this tutorial, you have learned garbage collection in Java with the help of important example programs. I hope that you will have understood the basic concepts of GC and practiced all programs. Stay tuned with the next tutorial where you will learn object finalization in Java with examples.
Thanks for reading!!!