All 7 Java Garbage Collectors Explained
Transcript:
Today we are talking about garbage collection in Java. Hotspot JVM offers seven garbage collectors for various performance requirements. Let's look at all of them.
But first, a couple of words about how Java memory model works. Garbage collection in Java is automatic. An object is considered eligible for GC when it becomes unreachable, meaning that there are no references to it. Such objects are deleted by the garbage collector. One of the functions of a Java garbage collection is managing objects in generations. Mul created objects belong to the young generation. As a rule, most objects die young, but if they don't, they are promoted to the old generation or tenure generation. These generations occupy different spaces on the JVM hip. Eden space and two survivor spaces zero and one are where young objects live. Tenure space preserves the old generation. Metaspace stores metadata. It replaced perm used in Java versions earlier than JDK8. When any of these spaces fill up, garbage collection occurs. A minor collection happens when the young space stops up. If some objects are still used at the moment of garbage collection, they are promoted to uh survivor space zero and then to survivor space one. If they're still alive in survivor space one, they are promoted to uh old generation. As a result, they are moved to the tenure space. At some point, tenure space also gets filled up and that's when the major collection occurs. Major collections usually take more time because more objects are involved.
And now let's look at various Java garbage collectors in more detail. Serial GC is the simplest and the oldest collector in Java. It works in one thread and freezes all application threads while performing the collection. It is good for single threaded client side applications that uh don't uh require extra small post times. But there is a catch. If you limit your application to 2 GB of RAM and less than two processors, then the serial GC is enabled by default even if you explicitly enable another collector. So be careful about that.
Parallel GC is also called the throughput collector. It also freezes all application threads but works in multiple threads to perform the collection. By default, it works in multiple threads when uh performing the collection of the young generation and the old generation. You can set the number of worker threads, post times, and the time the application spends on a collection.
Concurrent mark sweep GC was used in earlier Java versions. It was designed for shorter poses and used multiple threads to perform the collection, but it is suitable for applications that can afford to share processor resources with the garbage collector. This collector was duplicated in Java 9 and removed in Java 14. G1GC was designed to replace CMSGC. It is now default garbage collector in Java. G1GC tries to provide a good balance between latency and throughput. It is a good fit for applications uh running in multiprocessor environments with heaps of 10 GB and more. G1 means garbage first. Just like other collectors, it works with young and old generations.
However, it splits the heap into multiple equals sized regions. First, it performs the global marking phase to determine which objects are alive. It does it concurrently with the application. Then it reclaims the space in the regions that are mostly filled with garbage. This way, it can free more space. This is why it's called garbage first. It performs the collection using evacuation. It copies and compacts objects from one or several regions into one or several regions. This way it avoids memory fragmentation. You can also tune this collector. You can set pause times, pause intervals and so on. ZC was first introduced in Java 11. It is a scalable low latency collector which is perfect for latency sensitive applications and applications with a very large heap of terabytes. ZC performs the expensive work concurrently and doesn't stop the application threads for more than 10 milliseconds. It requires minimal configuration.
In most cases, you just uh enable this collector and set uh the heap size and you're good to go. In Java 23, it became generational by default. It means that it maintains uh separate generations for young and old objects and collects young objects more frequently. It improves heap memory overhead and the garbage collection CPU overhead. Shannonova GC is also a low latency collector. It was first introduced in Java 12. It performs most of its work concurrently with the application including concurrent compaction. Therefore, the pulse times are not directly proportional to the hip size. Like Zachy, it is suitable for latency sensitive applications and applications with large heaps of terabytes. It became generational by default in JDK25. Oracle Java doesn't ship Shannono GC but it is available uh with various open GDK distributions including libera GDK.
Epsilon GC is a very interesting collector. It doesn't perform garbage collection and only allocates memory. Why would you need a garbage collector that doesn't collect any garbage you may ask? Well actually it has a purpose. First, you can use it for performance testing to see how fast the application will run without any garbage collection and see whether there are any performance bottlenecks that are not related to garbage collection. Also, you can use it with applications that almost don't allocate any garbage or you can use it with shortlived applications that don't have time to produce any garbage. This way, they may run faster without the garbage collection cycles. Another interesting feature of epsilon GC is that it will remain experimental forever. This is done to avoid enabling it accidentally in the production. So to use epsilon GC you need to explicitly unlock experimental VM options. And that was it about available garbage collectors in hotspot JVM.





