Garbage Collection: A Brief Introduction


In this blog, I’m going to talk about how the used memory is freed in programming languages like C or C++ that do not offer automatic garbage collection, what are disadvantages of that process and how the garbage collector automatically helps in resolving this issue.

Memory management plays an important role in determining the performance of an application. It comprises of recognizing when allocated objects are no longer needed, deallocating the memory used by such objects, and eventually making it available for further use in allocating objects. Managing memory manually is a nontrivial and complex task as it can cause unexpected or erroneous program behavior and crashes.

Deallocating Memory Explicitly

Does handling memory manually sound great? Wait! We’ll see in a bit.

Traditional programming languages like C offers to deallocate the used memory manually. It is performed using the free() function. Let’s have a look at the below example,

int *ptr = (int*) malloc(sizeof(int));
 //do other memory stuff
 free(ptr);

Here, the ptr is allocated memory using malloc() function and after using it programmer deallocate it using free() function.

Problems in Managing Memory Explicitly

Following are the problems that occur while managing memory explicitly:

  1. Memory leaks   Consider a program in which you are trying to deallocate the memory used by the linked list. Suppose there is a small flaw in the part of the code that handles the deallocation of the memory of the head of a list.Then the remaining elements of the list will no longer be referenced. It will result in loss of some bytes of memory which cannot be recovered or used in future. These small losses are called memory leaks. After hundreds of iterations, all the remaining will be consumed and eventually the program will crash.
  2. Dangling references  – When the programmer deallocates the memory used by an object to which any other object still has a reference, then trying to access the original object would result in unpredictable behavior. Suppose there are two objects referring to the same memory location.
    dangling reference 1
    But accidentally developer deletes the obj1 and deallocate the memory then accessing obj2 would not give desired value.

dangling reference 2

Thus, managing memory explicitly will double the development effort for a more complex program.

Garbage Collection

Performance of the garbage collector is one key feature to the overall performance of any Java application. In Java, we don’t have to explicitly manage the lifecycle of objects i.e. objects are created when needed, and when the object is no longer in use, the JVM automatically frees the object. An object is eligible for garbage collection when no live thread can access it. The garbage collection revolves around to ensure that heap has enough memory available for allocating objects.

The basic process of garbage collection is explained below :

Step 1: Marking
In this step, the garbage collector identifies which objects are used and which objects are not.
marking

Step 2: Normal Deletion
The garbage collector removes the unused objects and reclaims the free space which can be used for further allocating other objects.
normal deletion

Step 3: Deletion with compaction
Since there can be free spaces left in small chunks at different location of the heap when the objects are freed,  there might be a chance that enough memory is not available in any one contiguous area for allocating objects that require large memory. Thus, to avoid such memory fragmentation scenario garbage collector does the process of compaction of memory.
deletion with compaction

How to explicitly make objects eligible for Garbage Collection?

In this section, we’ll learn how to explicitly make objects eligible for garbage collection using the actual code.

  1. Assign null to a Reference Variable

       By assigning null to a reference of an object will make it no longer accessible

      Integer x = new Integer(5);

       Here the Integer object is not eligible for collection
assigning null 1

       x = null;

assigning null 2At the point where an object, x, is assigned null it will make eligible for garbage collection and accumulated to the heap once the garbage collector runs for the cleanup process.

  2. Reassigning a Reference Variable

    StringBuffer s1 = new StringBuffer("Garbage");
    StringBuffer s2 = new StringBuffer("collection");

At this point, the object referred by s1 is not eligible for garbage collection
reassigning reference 1

    s1 = s2; // Redirects reference variable s1 to refer to the s2 object

reassigning reference 2
Now the object referred earlier by s1 is eligible for garbage collection as it cannot be accessed by any thread.

Another scenario that we’ll look into is when any other reference variable also points to the local variable are returned by a method.

We know that the lifetime of a local variable is up till the method is executing. Thus, an object created in the method will be eligible for garbage collection once the same method has completed its execution. The only exception is when an object is returned from the method, its reference may be assigned to some reference variable in the method that called it, then returned object will not be eligible for garbage collection. Below example will give better understanding,

class Student{
    int id;
    String name;
    public Student(int id, StringBuffer name) {
        this.id = id;
        this.name = name;
    }
    public Student makeStudentObject() {
        StringBuffer name = new StringBuffer(“Suyash”);
        Student s1 = new Student(1, name);
        return s1;
    }
    public static void main(String [] args) {
        Student s = makeStudentObject();
        //do other stuff
    }
}

Here, name and s1 are two local variable present in makeStudentObject() method. Student object, s1, is returned by method and it being inside main() method so it will not be eligible for garbage collection. But StringBuffer object, name, will be eligible for garbage collection as it not returned by a method.  In other words, s1 is still alive and name did not survive. Sad!

  3. Making anonymous objects

Since the reference to an anonymous object is not stored anywhere, so it can’t be accessed by any thread. Hence it can be regarded as another way of making objects which will be eligible for garbage collection. To understand it better let’s go through the below example,

class Employee {
         String empName;
         public Employee(String name) {
                 this.empName = name;
         }
         public static void main(String[] args) {
                 new Employee(“Avantika”); // anonymous object without any reference
                 // do other stuff
         }
 }

  4. Island of Isolation

Objects can become eligible for garbage collection, even if they have correct references. For example, a class has an instance variable that is a reference variable to another instance of the same class. Suppose there are three objects and they refer to each other (as shown below in the figure). If original references to the objects are removed, then even if they have a valid reference, they won’t be accessible. This condition is known as island of isolation.

class Student {
    Student s;
    public static void main(String [] args) {
        Student s1 = new Student();
        Student s2 = new Student();
        Student s3 = new Student();
        s1.s = s2; // s1 refers to s2
        s2.s = s3; // s2 refers to s3
        s3.s = s1; // s3 refers to s1
        s1 = null;
        s2 = null;
        s3 = null;
        // do other stuff
    }
}

island of isolation

Using the built-in methods for Garbage Collection

Should we use any predefined method for the garbage collection? NO! You might be wondering why when there is System.gc() or Runtime.gc() method available. Because invoking either of them does not guarantee all the unused objects will be removed. It will only make a request to JVM for some garbage collection.

The finalize() method

Java provides a finalize() method present in Object class which you can override for objects to do some task before it gets deleted by the garbage collector. But it is recommended not to use finalize() method as again it does not guarantee that it will run on every object. In general,

  1. For each object, finalize() method will be invoked at most ONCE by the garbage collector.
  2. The finalize() can severely affect the performance of the application.
  3. Any Exception thrown by finalize() method is ignored by GC thread and it will not be propagated further.

In my next blog, I will be discussing why heap is divided into different generations, different garbage collectors etc. Till then, Learn and share !!

This entry was posted in Java. Bookmark the permalink.

4 Responses to Garbage Collection: A Brief Introduction

  1. Prachi srivastava says:

    Nice article….

  2. Ankur says:

    How easily explained……very nice👌

  3. Sunny Agrawal says:

    What a wonderful pictorial representation about the topic…!!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s