Garbage Collection is a very important issues and often one of the reasons, why you cannot deliver your non-functional performance requirements. Finding the garbage collector which fits your purpose best is not always an easy task. Some developers do not even care about the selection of their garbage collector. Especially for those, the change coming with Java 9 will affect their applications performancewise.
What is the G1?
The G1 (“Garbage First”) is a Garbage Collector for the JVM which is available since JDK 7u4. With Java 9, the G1 Garbage collector will replace the Parallel GC as the default garbage collector. It can also handle heap-sizes with more than 6GB successful and has more predictable pause times.
The main goal of the G1 is, to lower the latency. This is based on the assumption, that limiting the pause time coming with garbage collection is more important, then maximizing the throughput of your application. This comes at the prize of some additional CPU-overhead.
Also important to mention is the G1’s ability to compact the heap on the go. In contrast, the Concurrent Mark Sweep Collector (CMS) does that only while running a full-collection.
As an icing on the cake, the G1 supports String deduplication (German), which can help to free even more memory, because a large portion of the heap is used up by Strings of which many are duplicated.
How does it work?
Usually, the heap maintained by an ordinary garbage collector looks like this:
The Garbage collector allocates a continues piece of heap-space for each generation and sub-generation of objects. These generations are defined by the lifetime of the objects, they contain. If an object survives long enough, it will eventually be moved from a young generation area to an older generation area. Because of the general assumption, that most objects die young, this results in some areas of the heap (permanent, old generation) to be rarely changed, while the part containing the young generation is changed very often.
Now it is very likely that the garbage collector only needs to go through the young-generation’s heap portion, instead of doing a full collection to free a reasonable amount of memory. But when the collector is mark-and-sweeping, all threads of the inhabiting application have to be paused (Stop the World).
The G1 has a more flexible approach. The heap structured by the G1 looks more like this:
As you see, the G1 partitions the heap into smaller, equal sized blocks and assigns them to a generation, instead of reserving one big space for the entire generation. The size of these blocks can be configured and varies between 1 and 32 MB.
Now, if the Garbage Collector performs its global marking phase (which is of course concurrent), it is able to sort the blocks by the amount of garbage they contain.
In the next step, the collector selects a number of blocks based on the pause-time-goal specified by the user. These blocks are of course the ones, that contain the most garbage. Because of this behavior, the G1 got its name “Garbage First”.
In the final step, the collector collects the selected blocks by evacuating their regions. That means, it copies the objects that are still alive from the different blocks together into a new region and removes the old regions entirely. This results in the heap being compacted on the go and avoiding compaction pauses.
Sometimes it happens, that all objects in an entire segment are not needed any more. So the collector is able to mark it as free in one step, instead of running its selecting and compacting algorithm on the block.
Additionally, there is the possibility to define state goals for the G1. These goals are defined as parameters and can include the size for the equal sized blocks (-XX:G1HeapRegionSize=n) or the maximum pause time (-XX:MaxGCPauseMillis=n) for the G1. The G1 will then optimize its behavior to meet these user defined goals by using its pause prediction algorithm. This algorithm is based on past collections and helps to select the best fitting number of blocks in each collection-cycle. This helps to fulfill the user’s goals and avoid full-collections.