Different Ways to Collect Garbage in Java HotSpot JVM
Last Updated :
08 Jun, 2023
JDKs come with different JVM implementations (Oracle HotSpot, Eclipse OpenJ9, GraalVM, Jikes RVM, Codename One), and different garbage collector implementations with different tuning options (Serial, Parallel, CMS, G1, Z, Shenandoah). In this article, we will know more about the Garbage Collector, how it works, and the various types of GC available in Java. We will also cover some of the new experimental Garbage Collectors that are available in the latest Java releases.
What is Garbage Collection in Java?
In C/C++, a programmer is responsible for both the creation and destruction of objects. Usually, programmer neglects the destruction of useless objects. Due to this negligence, at a certain point, sufficient memory may not be available to create new objects, and the entire program will terminate abnormally, causing OutOfMemoryErrors. We can use methods like free() in C, and delete() in C++ to perform Garbage Collection. In Java, garbage collection happens automatically during the lifetime of a program. This eliminates the need to de-allocate memory and therefore avoids memory leaks. Garbage Collection is the process by which we can reclaim the runtime unused memory by destroying the unused objects.
The objects created in the Java program are present in the heap memory of Java. Most of you would already be familiar with that. An object is eligible for garbage collection if there are no references to it in the heap memory. There are various ways in which the references to an object can be released to make it a candidate for Garbage Collection. Some of them are:
1. By Making Reference to object Null
Java
Student studentOne = new Student();
studentOne = null ;
|
2. By Using an anonymous object
3. By Pointing one’s reference to another object or reference
Java
Student studentOne = new Student();
Student studentTwo = new Student();
studentOne = studentTwo;
|
4. An Object created inside a method loses reference outside the method
Java
public void function(){
Student studentOne = new Student();
}
public static void Main(){
function();
}
|
Heap Memory Division
The heap memory area in the JVM is divided into three sections:
- Young Generation: All New Objects are first stored here.
- Old Generation: Large objects are allocated memory here. Also, the objects in the young generation who survived minor garbage collection processes of the young generation are promoted here.
- Permanent Generation: Here the objects or metadata which are required by JVM for describing classes and methods are stored. This memory also stores classes as well as methods.
Heap Memory
Types of Garbage Collectors in HotSpot Java
There are mainly 4 algorithms for garbage collectors in HotSpot Java:
1. Serial Garbage Collection
It is used where just one thread executed the GC (garbage collection). This collector freezes all application threads whenever it’s working. If we want to use the serial garbage collector, execute the -XX:+UseSerialGC JVM argument to activate it.
Serial GC
2. Parallel Garbage Collection
Where multiple minor threads are executed simultaneously. This collector also freezes all application threads whenever it’s working. If you want to use the parallel garbage collector, execute the -XX:+UseParallelGC JVM argument to activate it.
Parallel GC
3. Concurrent Mark Sweep(CMS) Garbage Collection
It is similar to parallel, also allows the execution of some application threads, and reduces the frequency of stop-the-world GC. It has 2 phases: Mark Phase and Sweep Phase. The Mark phase algorithm marks all the live objects in heap memory (those that have a reference) as “live” and others as “dead” while putting the applications on pause. The Sweep phase algorithm empties the space occupied by objects marked “dead”. In the Mark phase, multiple minor threads are executed simultaneously to mark the live objects. In the Sweep phase, multiple minor threads are executed simultaneously to sweep or delete the dead objects parallel to application threads. For this reason, it uses more CPU in comparison to other GC. It is also known as the concurrent low pause collector. If you want to use a CMS garbage collector, execute the -XX:+USeParNewGC JVM argument to activate it. We can also set the number of GC threads by using the -XX:ParallelCMSThreads=<n> JVM argument.
CMS Garbage Collection
Note: The Concurrent Mark Sweep (CMS) collector is deprecated as of JDK 9, with the recommendation to use the G1 collector instead.
4. Generation First(G1) Garbage Collection
This GC is used if we have huge memory(>4GB). It partitions the heap into a set of equal size regions (1MB to 32MB - depending on the size of the heap) and uses multiple threads to scan them and mark the objects as live or dead. After marking, G1 knows which regions contain the most garbage objects. In the next step, it sweeps the objects in the region containing most garbage objects. G1 works concurrently with the application. This divides young and old generations of the heap into the following regions:
- Eden region in memory where the objects are typically allocated when they are created.
- Survivor Region contains the objects that have survived from the Young garbage collection or Minor garbage collection.
- Tenured Region is where long-lived objects are stored. Objects are eventually moved to this space if they survive a certain number of garbage collection cycles. This space is much larger than the Eden space and the garbage collector checks it less often.
- Humongous: It is used if the object size is large.
- Available: It represents the unoccupied space.
An optimization is present in Java 8 (G1 Collector String deduplication). Since strings (and their internal char[] arrays) takes much of our heap, a new optimization has been made that enables the G1 collector to identify strings that are duplicated more than once across heap memory and correct them to point to the same internal char[] array, to avoid multiple copies of the same string from residing inefficiently within the heap. If you want to use G1 GC use -XX:+UseStringDeduplicationJVM argument.
G1 GC Space Description
5. Z Garbage Collector
It’s the latest GC that can be used with Java 11 by explicitly setting it, and in Java 15 and beyond this is set as default. It’s a highly scalable, low-latency GC. It performs very expensive tasks concurrently without stopping the working of threads for more than 10ms. It can work on large heap memory (up to TBs). If you want to use ZGC, use XX:+UnlockExperimentalVMOptions -XX:+UseZGC.
ZGC Heap Regions
Methods for Running Garbage Collector in Java
In Java, GC runs by itself. But there are some methods we can use in Java:
- System.gc()
- Runtime.getRuntime().gc()
Best Practices to Use Garbage Collection
Collector choice is a primary concern as the wrong collector can hinder performance and render the application useless. For backend purposes, the CMS collector can prove to be useful in spite of having the disadvantage of stopping the application itself during garbage collection. However, the frontend of the application must not implement CMS because the UI must always be responsive. This calls for G1 collectors which can run concurrently with the application in itself. ZGC is the newest and provides very low latency and high throughput which can be used by applications that require low latency and uses large-size Heap. Whenever you are using garbage collections in Java it is important to note that you can never predict when the garbage collector will run. You can try to explicitly call the garbage collector by System.gc() and Runtime.gc(). However, even after explicitly calling the Garbage collector there is no guarantee that it will actually work.