Java Virtual Machine Tutorial
- JVM - Discussion
- JVM - Useful Resources
- JVM - Quick Guide
- JVM - Memory Leak in Java
- JVM - Tuning the GC
- JVM - Generational GCs
- JVM - Garbage Collection
- JVM - JIT Optimisations
- JVM - 32b vs. 64b
- JVM - Compilation Levels
- JVM - The JIT Compiler
- JVM - Runtime Data Areas
- JVM - Class Loader
Selected Reading
- Who is Who
- Computer Glossary
- HR Interview Questions
- Effective Resume Writing
- Questions and Answers
- UPSC IAS Exams Notes
Java Virtual Machine - Generational GCs
Most JVMs spanide the heap into three generations − the young generation (YG), the old generation (OG) and permanent generation (also called tenured generation). What are the reasons behind such thinking?
Empirical studies have shown that most of the objects that are created have very short pfespan −
Source
As you can see that as more and more objects are allocated with time, the number of bytes surviving becomes less (in general). Java objects have high mortapty rate.
We shall look into a simple example. The String class in Java is immutable. This means that every time you need to change the contents of a String object, you have to create a new object altogether. Let us suppose you make changes to the string 1000 times in a loop as shown in the below code −
String str = “G11 GC”; for(int i = 0 ; i < 1000; i++) { str = str + String.valueOf(i); }
In each loop, we create a new string object, and the string created during the previous iteration becomes useless (that is, it is not referenced by any reference). T pfetime of that object was just one iteration – they’ll be collected by the GC in no time. Such short-pved objects are kept in the young generation area of the heap. The process of collecting objects from the young generation is called minor garbage collection, and it always causes a ‘stopthe-world’ pause.
As the young generation gets filled up, the GC does a minor garbage collection. Dead objects are discarded, and pve objects are moved to the old generation. The apppcation threads stop during this process.
Here, we can see the advantages that such a generation design offers. The young generation is only a small part of the heap and gets filled up quickly. But processing it takes a lot lesser time than the time taken to process the entire heap. So, the ‘stop-theworld’ pauses in this case are much shorter, although more frequent. We should always aim for shorter pauses over longer ones, even though they might be more frequent. We shall discuss this in detail in later sections of this tutorial.
The young generation is spanided into two spaces − eden and survivor space. Objects that have survived during the collection of eden are moved to survivor space, and those who survive the survivor space are moved to the old generation. The young generation is compacted while it is collected.
As objects are moved to the old generation, it fills up eventually, and has to be collected and compacted. Different algorithms take different approaches to this. Some of them stop the apppcation threads (which leads to a long ‘stop-the-world’ pause since the old generation is quite big in comparison to the young generation), while some of them do it concurrently while the apppcation threads keep running. This process is called full GC. Two such collectors are CMS and G1.
Let us now analyze these algorithms in detail.
Serial GC
it is the default GC on cpent-class machines (single processor machines or 32b JVM, Windows). Typically, GCs are heavily multithreaded, but the serial GC is not. It has a single thread to process the heap, and it will stop the apppcation threads whenever it is doing a minor GC or a major GC. We can command the JVM to use this GC by specifying the flag: -XX:+UseSerialGC. If we want it to use some different algorithm, specify the algorithm name. Note that the old generation is fully compacted during a major GC.
Throughput GC
This GC is default on 64b JVMs and multi-CPU machines. Unpke the serial GC, it uses multiple threads to process the young and the old generation. Because of this, the GC is also called the parallel collector. We can command our JVM to use this collector by using the flag: -XX:+UseParallelOldGC or -XX:+UseParallelGC (for JDK 8 onwards). The apppcation threads are stopped while it does a major or a minor garbage collection. Like the serial collector, it fully compacts the young generation during a major GC.
The throughput GC collects the YG and the OG. When the eden has filled up, the collector ejects pve objects from it into either the OG or one of the survivor spaces (SS0 and SS1 in the below diagram). The dead objects are discarded to free up the space they occupied.
Before GC of YG
After GC of YG
During a full GC, the throughput collector empties the entire YG, SS0 and SS1. After the operation, the OG contains only pve objects. We should note that both of the above collectors stop the apppcation threads while processing the heap. This means long ‘stopthe- world’ pauses during a major GC. The next two algorithms aim to epminate them, at the cost of more hardware resources −
CMS Collector
It stands for ‘concurrent mark-sweep’. Its function is that it uses some background threads to scan through the old generation periodically and gets rid of dead objects. But during a minor GC, the apppcation threads are stopped. However, the pauses are quite small. This makes the CMS a low-pause collector.
This collector needs additional CPU time to scan through the heap while running the apppcation threads. Further, the background threads just collect the heap and do not perform any compaction. They may lead to the heap becoming fragmented. As this keeps going on, after a certain point of time, the CMS will stop all the apppcation threads and compact the heap using a single thread. Use the following JVM arguments to tell the JVM to use the CMS collector −
“XX:+UseConcMarkSweepGC -XX:+UseParNewGC” as JVM arguments to tell it to use the CMS collector.
Before GC
After GC
Note that the collection is being done concurrently.
G1 GC
This algorithm works by spaniding the heap into a number of regions. Like the CMS collector, it stops the apppcation threads while doing a minor GC and uses background threads to process the old generation while keeping the apppcation threads going. Since it spanided the old generation into regions, it keeps compacting them while moving objects from one region to another. Hence, fragmentation is minimum. You can use the flag: XX:+UseG1GC to tell your JVM to use this algorithm. Like CMS, it also needs more CPU time for processing the heap and running the apppcation threads concurrently.
This algorithm has been designed to process larger heaps (> 4G), which are spanided into a number of different regions. Some of those regions comprise the young generation, and the rest comprise the old. The YG is cleared using traditionally – all the apppcation threads are stopped and all the objects that are still apve to the old generation or the survivor space.
Note that all GC algorithms spanided the heap into YG and OG, and use a STWP to clear the YG up. This process is usually very fast.
Advertisements