Java Garbage Collection – ‘Coz there’s no space for unwanted stuff in Java

Garbage Collection is one of the most important features in Java which makes it popular among all the programming languages. The process of garbage collection is implicitly done in Java.

Therefore, it is also called Automatic Garbage Collection in Java. The programmer does not need to explicitly write the code to delete the objects.

Today in this article, we are going to learn the concept of Garbage Collection in Java in detail, along with its methods and algorithms.

But before that have you checked out our previous article on Wrapper Class in Java? If not then you must surely take a quick sneak peek of Wrapper Class in Java to clear your basics with Techvidvan.

Let’s start discussing the concept of the Garbage Collection in Java.

Types of Garbage Collection in Java

Garbage Collection in Java

Garbage collection is the technique used in Java to deallocate or remove unreachable objects and unused memory. From the name itself, we can understand that Garbage Collection deals with tracking and deleting the garbage from the memory area.

However, in reality, Garbage Collection tracks each and every object available in the JVM heap space and removes the unused ones.

We know that all the objects that we dynamically create are allocated in the heap memory of the application. Normally, it is the duty of the programmer to both create and delete the objects in the program, but the programmer usually ignores the deletion of the object.

This creates a problem of OutOfMemoryErrors due to insufficient memory because of not deleting the unwanted objects.

In Java, the programmer does not have to worry about the problem of releasing the memory of these unused or unwanted objects, as the garbage collection system always runs in the background, and its main aim is to free the memory heap by deleting unreachable objects.

Essentially, Garbage Collection is the process of tracking down all the objects that are still in use and marking the rest of them as garbage.

The Garbage Collection process in Java is considered an automatic memory management schema because programmers do not have to explicitly deallocate the objects. The garbage collection in Java runs on low-priority threads.

The implementation of the Garbage Collection is present in the JVM (Java Virtual Machine). Each JVM can implement garbage collection. But there is only one requirement;

that it should meet the JVM specification. Oracle’s HotSpot is one of the most common JVMs that offers a robust and mature set of garbage collection options.

Object Life Cycle in Java

The object life cycle in Java can be divided into 3 stages:

1. Object Creation

To create an object, generally, we use a new keyword. For example:

MyClass obj = new MyClass();

We created the object obj of class MyClass. When we create the object, a specific amount of memory is allocated for storing that object. The amount of memory allocated for objects can vary on the basis of architecture and JVM.

2. Object Usage

In this stage, the Object is in use by the other objects of the application in Java. During its usage, the object resides in memory and may refer to or contain references to other objects.

3. Object Destruction

The garbage collection system monitors objects and keeps a count on the number of references to each object. There is no need for such objects in our programs if there are no references to this object, so it makes perfect sense to deallocate this unused memory.

Unreachable Objects in Java

When an object does not contain any “reachable” reference to it, then we call it an unreachable object. These objects can also be known as unreferenced objects.

Example of unreachable objects: 

Double d = new Double(5.6);
// the new Double object is reachable via the reference in 'd'
d = null;
// the Integer object is no longer reachable. Now d is an unreachable object.

Unreachable Object in Java Example

Eligibility for Garbage Collection in Java

An object can be eligible for garbage collection in Java if and only if it is unreachable. In the above program, after declaring d as null; double object 4 in the heap area becomes eligible for garbage collection.

Object Eligibility

Though Java has automatic garbage collection, an object should be made unreachable manually. There are different ways to know whether the object is eligible for Garbage Collection in Java.

There are generally four ways in Java to make an object eligible for garbage collection:

  • Nullifying the reference variable
  • Reassigning the reference variable
  • Island of isolation
  • Creating objects inside a class

Dive a little deep into the concept of Variables of Java with Techvidvan.

Ways of requesting JVM to run Garbage Collector

Even if we make an object eligible for Garbage Collection in Java, it may or may not be eligible for Java Virtual Machine (JVM) to destroy. So there are some ways to request JVM to destroy this object and perform garbage collection.

There are two ways to request JVM for Garbage collection in Java which are:

  • Using System.gc() method
  • Using Runtime.getRuntime().gc() method

Code to understand the above two methods:

package com.techvidvan.garbagecollection;
public class Demo
{
  public static void main(String[] args) throws InterruptedException
  {
    Demo obj1 = new Demo();
    Demo obj2= new Demo();

    // requesting JVM for running Garbage Collector
    System.gc();
    // Nullifying the reference variable
    obj2 = null;
    // requesting JVM for running Garbage Collector
    Runtime.getRuntime().gc();
  }
  @Override
  // finalize method is called on object once before garbage collecting it
  protected void finalize() throws Throwable
  {
    System.out.println("Garbage Collector ");
    System.out.println("Garbage collected object: " + this);
  }
}

Output:

Garbage Collector
Garbage collected object: com.techvidvan.garbagecollection.Demo@17f18626

Before removing an object from memory, the garbage collection thread invokes the finalize() method of that object and gives an opportunity to perform any sort of cleanup required.

A Real-life Example of Garbage Collection

Let’s take a real-life example of a garbage collector.

Suppose you go for an internship at a particular company and you have to write a program that counts the number of employees working in the company, excluding interns. To implement this task, you have to use the concept of a garbage collector.

The actual task given by the company:

Question. Write a program to create a class Employee having the following data members.

  1. An ID for storing unique id for every employee.

And, the class will have the following methods:

  1. A default constructor to initialize the id of the employee.
  2. A method show() to display ID.
  3. A method showNextId() for displaying the ID of the next employee.

Any beginner, who doesn’t know the concept of garbage collector will write the following code to count the number of employees:

Code to count the number of employees in the company without using garbage collection:

class Employee
{
  private int ID;

  private static int nextId=1;
  //we make it static because it should be common among all and shared by all the objects
  public Employee()
  {
    this.ID = nextId++;
  }
  public void show()
  {
    System.out.println("Id=" +ID);
  }
  public void showNextId()
  {
    System.out.println("Next employee id will be="+nextId);
  }
}
public class CountEmployees
{
  public static void main(String args[])
  {
    Employee A=new Employee();
    Employee B=new Employee();
    Employee C=new Employee();
    A.show();
    B.show();
    C.show();

    A.showNextId();
    B.showNextId();
    C.showNextId();

    {
      //It is a sub block to keep all those interns.
      Employee X=new Employee();
      Employee Y=new Employee();
      X.show();
      Y.show();
      X.showNextId();
      Y.showNextId();
    }
    //After this brace, X and Y will be removed.
    //Therefore, now it should show nextId as 4.
    A.showNextId();
    //Output of this line should be 4 but the output we will get is 6.
  }
}

Output:

Id=1
Id=2
Id=3
Next employee id will be=4
Next employee id will be=4
Next employee id will be=4
Id=4
Id=5
Next employee id will be=6
Next employee id will be=6
Next employee id will be=6

Now to get the correct output:

If we write the same code using the garbage collection technique, the garbage collector will see that the two objects are free. To decrement the value of the variable nextId, the garbage collector will call the finalize() method only when the programmers override it in their class.

And as we know that we have to request a garbage collector, and to do this, we have to write the following three steps before closing the brace of sub-block.

  1. Set references to null (that is, X = Y = null;)
  2. Call System.gc();
  3. Call System.runFinalization();

Correct Code to count the number of employees (excluding interns) using garbage collection

//Correct code to count the number of employees excluding interns.
class Employee
{
  private int ID;
  private static int nextId=1;
  //we declare it static because it should be common among all and shared by all the objects
  public Employee()
  {
    this.ID = nextId++;
  }
  public void show()
  {
    System.out.println("Id="+ID);
  }
  public void showNextId()
  {
    System.out.println("Next employee id will be="+nextId);
  }
  protected void finalize()
  {
    --nextId;
    //In this case,
    //gc will call finalize()
    //for 2 times for 2 objects.
  }
}
public class CountEmployees
{
  public static void main(String args[])
  {
    Employee A=new Employee();
    Employee B=new Employee();
    Employee C=new Employee();
    A.show();
    B.show();
    C.show();
    A.showNextId();
    B.showNextId();
    C.showNextId();

    {
      //It is a sub-block to keep all those interns.
      Employee X=new Employee();
      Employee Y=new Employee();
      X.show();
      Y.show();
      X.showNextId();
      Y.showNextId();
      X = Y = null;
      System.gc();
      System.runFinalization();
    }
    E.showNextId();
  }
}

Output:

Id=1
Id=2
Id=3
Next employee id will be=4
Next employee id will be=4
Next employee id will be=4
Id=4
Id=5
Next employee id will be=6
Next employee id will be=6
Next employee id will be=4

Garbage Collection Algorithms in Java

Garbage Collection Algorithms in Java helps to remove the unreferenced or unreachable objects. These algorithms always run in the background.

There are several different types of Garbage Collection Algorithms in Java that run in the background. And among them, one of the algorithms is a Mark and Sweep algorithm.

Mark and Sweep Algorithm

Mark and Sweep algorithm is a fundamental and initial algorithm for Garbage Collection in Java. This algorithm basically performs two primary functions: mark and sweep.

Firstly, it should track and detect unreachable objects and, secondly, it should release these objects from the memory heap area so that the programmer can use it again.

1. Mark phase – Mark live objects

It is the first phase of the algorithm in which there is the detection of all the objects that are still alive. It is a stage where the garbage collector identifies which parts of memory are in use and which are not in use.

In this phase when the condition is made, its check bit is set to 0 or false. We set the marked bit to 1 or true for all the reachable objects.

Here we can consider each object as a node and then we visit all the objects or nodes that are reachable from this object/node, and it repeats until we have visited all the reachable nodes.

  • The root is a variable that refers to an object and is directly accessible by a local variable. We will assume that we have only one root.
  • We can use markedBit(obj) to access the mark bit for an object.

Mark Phase Algorithm:

Mark(root)
If markedBit(root) = false then
    markedBit(root) = true
    For each v referenced by a root
         Mark(v)

Note: We can call Mark() for all the root variables if we have more than one root.

2. Sweep phase – Get rid of dead objects

The sweep phase algorithm “clears” all the inaccessible or unreachable objects that is, it releases the stored memory area for all the inaccessible objects.

Each of the items whose check value is set to false is removed from the stack memory, for every single other reachable object, we set the value of the stamped bit to false.

Presently the check bit for all the reachable objects is set to false.

Sweep Collection Algorithm:

Sweep()
For each object p in a heap
    If markedBit(p) = true then
       markedBit(p) = false
    else
       heap.release(p)

‘Mark and Sweep’ algorithm is also called a tracing garbage collector because this algorithm is used to trace the objects. For example

  • Marked bits set to false.
  • Reachable objects are set to true.
  • Non-reachable objects get clear from the heap.

Advantages of the Mark and Sweep Algorithm

  • It is a cyclic process.
  • There are no additional overheads that occur during the execution of an algorithm.

Disadvantages of the Mark and Sweep Algorithm

  • While the Java garbage collection algorithm runs, normal program execution stops.
  • It runs differently several times on a program.

Implementations or Types of Garbage Collection

JVM has four types of Garbage Collector implementations which are –

  • Serial Garbage Collector
  • Parallel Garbage Collector
  • CMS Garbage Collector
  • G1 Garbage Collector

Now, we will briefly discuss each type of garbage collector.

1. Serial Garbage Collector

It is the simplest Garbage Collector implementation as it basically works with a single thread and all the garbage collection events are conducted serially in one thread. As this collector can work on a single thread, it freezes all application threads when it runs.

Hence, it is not preferred to use it in multi-threaded applications like server environments.

We can use the following argument to enable Serial Garbage Collector:

java -XX:+UseSerialGC -jar Application.java

2. Parallel Garbage Collector

It is the default Garbage Collector of the JVM and sometimes called Throughput Collectors. Unlike the Serial Garbage Collector, the Parallel Garbage Collector uses multiple threads to manage heap space.

But at the same time, it also suspends other application threads while performing garbage Collection. Using this Garbage Collector, we can specify the maximum garbage collection threads throughput and footprint (heap size) and, pause time.

We can use the following argument to enable Parallel Garbage Collector,

java -XX:+UseParallelGC -jar Application.java

3. CMS (Concurrent Mark Sweep) Garbage Collector

The CMS Garbage Collection implementation uses multiple threads for garbage collection. This Garbage Collector is designed for applications that can afford to share processor resources with the garbage collector while the application is running and that prefer shorter garbage collection pauses.

Simply we can say that applications using CMS respond slower on average but do not stop responding to perform garbage collection.

We can use the following flag to enable the CMS Garbage Collector:

java -XX:+UseParNewGC -jar Application.java

4. G1(Garbage First) Garbage Collector

G1 (Garbage First) Garbage Collector is the newest garbage collector which is designed as a replacement for CMS. It performs more efficiently as compared to CMS Garbage Collector.

It is similar to CMS and is designed for applications running on multiprocessor machines with large memory space.

To enable the G1 Garbage Collector, we can use the following argument:

java -XX:+UseG1GC -jar Application.java

Advantages of Garbage Collection:

  • There is no need to manually handle the memory allocation/deallocation because the JVM automatically performs the Garbage Collection for unused space in Java.
  • There is no overhead of handling the Dangling Pointer.
  • Garbage Collection takes care of a good portion of Automatic Memory Leak management.

Disadvantages of Garbage Collection:

  • There is a more requirement of CPU power besides the original application, as JVM has to keep track of object reference creation/deletion. This may affect the performance of requests which require a huge memory.
  • Programmers do not have any control over the scheduling of CPU time dedicated to freeing the unreachable objects.
  • Using some Garbage Collection implementations an application may stop unpredictably.
  • Automatic memory management is not much efficient proper manual memory allocation/deallocation.

Summary

Garbage Collection in Java is useful for preventing memory leaks and for utilizing the space. In this Java tutorial, we learned about the garbage collection in Java and its working. We discussed the important terms related to Java Garbage Collection.

We also covered the algorithm for garbage collection. There are four types of Java Garbage Collectors which we learned in this article. We discussed the Java Mark and Sweep algorithm along with its pros and cons.

We also had a look at the advantages and disadvantages of the Garbage Collection in Java.

Hope this article helped you in clearing your concepts in Garbage Collection.

Thank you for reading our article. Do share your feedback through the comment section below.

TechVidvan Team

The TechVidvan Team delivers practical, beginner-friendly tutorials on programming, Java, Python, C++, DSA, AI, ML, data Science, Android, Flutter, MERN, Web Development, and technology. Our experts are here to help you upskill and excel in today’s tech industry.