Let’s start discussing the concept of the 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.
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
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.oraclejavacertified.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.oraclejavacertified.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.
0 comments:
Post a Comment