In this article we will cover the proper use of Garbage Collection. Let us learn how it works, and understand how to induce the Garbage Collection. The Garbage Collection is a tool coupled to the JVM, that performs cleanup of objects in memory (Read: static utility for objects) which are of no further use. Our application will constantly suffer from a lack of memory without this tool or better known as “memory leak“.
For those who are from the C language background they can use it manually to release objects in memory using the command free. To use this command we should know which object we want to release and exactly to at what moment. But Java is different, because you can not demonstrate and release objects in memory, it is responsible for making the garbage collection , and you (as a developer) will have no control over it.
Actually you can just suggest it to do the cleaning of a particular object, but it is not guaranteed that it will be done, It would be a big mistake by developing an application that relies heavily on the cleanliness of Garbage Collection. Java does not allow us to release objects in memory explicitly, for it has to be Garbage Collected. Let us now understand how this tool works and what are the advantages of having that “extra” feature offered by the JVM.
Operation of Garbage Collection
When you use the reserved word new in Java, you are creating an object in memory and a pointer that will point to this object. Nothing better than an example to illustrate this, you can see an example in Listing 1. The code is well commented throughout to illustrate the function of each item in Student class.
Listing 1 : Let us understand how to create the objects and pointers in memory.
package net.javabeat; public class Student { int a; int b; /** * Assign new values for the atributes a and b of our Student object **/ public void setData(int newA, int newB) { a = newA; b = newB; } /** * Displays the values of a and b of object Student **/ public void showData() { System.out.println("Value of a = " + a); System.out.println("Value of b = " + b); } public static void main(String args[]) { /** * We have created a Student object in memory called S1 and a * pointer that will point to this object. **/ Student s1 = new Student(); /** * We have created a Student object in memory called S2 and a pointer * that will point to this object. **/ Student s2 = new Student(); /** * So far our objects referenced by s1 and s2 has no value * we will set data in the attributes a and b **/ s1.setData(1, 2); s2.setData(3, 4); /** Show the values set in the objects s1 and s2 to user **/ s1.showData(); s2.showData(); } }
The JVM stores objects in the HEAP memory, so let’s see how is HEAP memory after running the above code.
Figure 1 : HEAP memory after execution of Listing 1
S1 and S2 are just pointers to our objects created by the reserved word new, they are not the object itself. It is very important to understand the operation of the GC (Garbage Collection) . Our first object (the right side, referenced by S1) has values 1 and 2 for a and b respectively, while our second object (referenced by S2) has values of 3 and 4 for a and b respectively. It turns out that at present none of the above objects is eligible to be cleaned by the GB, because each one has a reference in memory, and another one with S1 to S2.
We will now add a few lines to our code to create two references to the same object.
Example Listing 2 : Creating a reference s3
<pre>package net.javabeat; public class Student { int a; int b; /** * Assign new values for the atributes a and b of our Student object **/ public void setData(int newA, int newB) { a = newA; b = newB; } /** * Displays the values of a and b of object Student **/ public void showData() { System.out.println("Value of a = " + a); System.out.println("Value of b = " + b); } public static void main(String args[]) { /** * We have created a Student object in memory called S1 and a pointer * that will point to this object. **/ Student s1 = new Student(); /** * We have created a Student object in memory called S2 and a pointer * that will point to this object. **/ Student s2 = new Student(); /** * So far our objects referenced by s1 and s2 has no value we will set * data in the attributes a and b **/ s1.setData(1, 2); s2.setData(3, 4); /** Show the values set in the objects s1 and s2 to user **/ s1.showData(); s2.showData(); /** * We create a new reference to the same object that s2 Is pointing **/ Student s3; s3 = s2; s3.showData(); }
Here’s a pictorial view of the memory as below:
Figure 2 : New reference S3
Note that we have the same object, but referenced by 2 different pointers. Let us understand and begin using GC .
But before that, keep in mind the following concept: Objects eligible to be deleted by the GC, are those who no longer have any reference in memory, ie, have no pointer pointing to it, so they become objects “lost “in memory because we can not get it back, and GC can delete them at any time.
Keeping the above concept in mind, we will set the value to null s2 and see what happens in our memory HEAP.
Example Listing 3 : Setting the value to null s2.
package net.javabeat; public class Student { int a; int b; /** * Assign new values for the atributes a and b of our Student object **/ public void setData(int newA, int newB) { a = newA; b = newB; } /** * Displays the values of a and b of object Student **/ public void showData() { System.out.println("Value of a = " + a); System.out.println("Value of b = " + b); } public static void main(String args[]) { /** * We have created a Student object in memory called S1 and a pointer * that will point to this object. **/ Student s1 = new Student(); /** * We have created a Student object in memory called S2 and a pointer * that will point to this object. **/ Student s2 = new Student(); /** * So far our objects referenced by s1 and s2 has no value we will set * data in the attributes a and b **/ s1.setData(1, 2); s2.setData(3, 4); /** Show the values set in the objects s1 and s2 to user **/ s1.showData(); s2.showData(); /** * We create a new reference to the same object that s2 Is pointing **/ Student s3; s3 = s2; s3.showData(); /** * We set the pointer value of s2 to null , so it does not make * reference to any object */ s2 = null; s3.showData(); } }
Since s2 does not point to an object, GC can now delete this object from memory, correct? Wrong, because s3 is still pointing to our object. See Figure 3.
Figure 3 : s2 pointing to null
Both objects still have references in memory, then the GC can not delete them. Let us take the reference from object s3.
Listing 3 : Setting tab s3 to zero
package net.javabeat; public class Student { /** * Assign new values for the atributes a and b of our Student object **/ public void setData(int newA, int newB) { a = newA; b = newB; } /** * Displays the values of a and b of object Student **/ public void showData() { System.out.println("Value of a = " + a); System.out.println("Value of b = " + b); } public static void main(String args[]) { /** * We have created a Student object in memory called S1 and a pointer * that will point to this object. **/ Student s1 = new Student(); /** * We have created a Student object in memory called S2 and a pointer * that will point to this object. **/ Student s2 = new Student(); /** * So far our objects referenced by s1 and s2 has no value we will set * data in the attributes a and b **/ s1.setData(1, 2); s2.setData(3, 4); /** Show the values set in the objects s1 and s2 to user **/ s1.showData(); s2.showData(); /** * We create a new reference to the same object that s2 Is pointing **/ Student s3; s3 = s2; s3.showData(); /** * We set the pointer value of s2 to null , so it does not make * reference to any object */ s2 = null; s3.showData(); /** * We will lose an object reference s3, as it will not have the * reference to s2 or s3, hence showdata will be impossible to perform **/ s3 = null; } }
We can see in the diagram, we now have one object which is eligible to be deleted by the GC.
Figure 4 : No Object reference
Okay, now when the GC is performing cleanup, this object is removed, because it has no reference in memory. We also ask the GC to perform a cleanup using the command System.gc (), but as we said, it is not guaranteed that it will run at a specific time.
Summary
The main goal of this tutorial was to show how the GC works by cleaning the objects in memory. This required us to understand how it refers to objects in memory, and their values. We have published few articles on memory storage that would be helpful for you to understand this concepts better. Please read Visualizing Memory Usage with VisualVM, Java Memory Model, and Memory Leak Detector.