It's Past Time to Upgrade
posted Thursday, 28 August 2008
If your application is still running on the 1.4 or even 1.5, a compelling argument to upgrade to Java 6 is just over the eastern horizon. That reason is the Garbage First Garbage Collector otherwise known as G1. After I explain how it works, I’ll explain why I think this collector is about to change the face of GC.
As revolutionary as the effects that I expect to see produced by the G1 collector, the collector it’s self is only an evolutionary step away from the generational collectors that we know use. If you are a GC gear head, then you know that Java heap is divided into 3 spaces, young, tenured, and perm. You know that young is further divided into eden and two survivor spaces. When eden fills up, the collector finds all live objects and evacuates them to one of the survivor spaces. Older objects will eventually find themselves in tenured space. This division allows us to treat younger objects differently than we treat older objects. The GC implementors knew that young objects tend to die very quickly. This fact is known as the “Weak Generational Hypothesis”.
Since most objects die within a few 10s to 100s of microseconds, when eden is “full”, only very few of the objects are live. These surviving objects can quickly be copied to a survivor space and mark the entire space as free. I started calling this Object Harvesting as opposed to Garbage Collection because I feel it more accurately reflects what is going on. Now because we don’t collect but only harvest, young generational GC (harvesting??) is very cheap. The same evacuation technique can be used for the survivor spaces making those spaces cheap to manage also. However, there is no space to evacuate from tenured to and consequently, full GCs remain some what expensive. I expect that with the G1 collector, this is about to change.
The G1 collector, memory will be divided into (currently) 1 megabyte buffers. Each of these buffers will participate in a generation. Some will be assigned to young, some to survivor, and others to old. The collector will be parallelized (multi-threaded) and will work concurrently with your application. While the activities of the young collection will be somewhat the same as it is today, the biggest change will be in the collection of tenured spaces.
The first phase of collection is to mark all live objects. In young spaces, all live objects will be harvested (copied) to an empty space (survivor). In tenured, the mark phase will be used to calculate the liveliness of a space. Spaces that are 100% clean will be put back on the free list. Spaces that have a low liveliness will be put into a list of candidate spaces to be collected (err, harvested). When a young generation collection occurs, that collector will grab a couple of these low liveliness spaces and harvest them. In other words, there will no longer be a separate tenured space collector. This notion is reflected in G1s nickname, the 1 1/2 garbage collector.
Why is this going to be better than what we have now? Currently is we want a low latency collector, we must resort to using the Concurrent Mark and Sweep (CMS) collector. While this does a great job of increasing liveliness of our applications by reducing that stop-the-world nature of GC that we’ve all grown to know and love, CMS can still create some devastating pause times. It does this because CMS does not compact. A non compacting collector will eventually leave your heap looking like swiss cheese and when it does, it needs to compact. If you need to compact you need to stop all application threads and performing memory to memory copying to eliminate these holes as well as free list management ain’t cheap.
In fact the cost of copying objects was one of the reasons we didn’t have a generational collector for so long. The engineers figured that the cost of copying would far out-weigh the benefits. This is evidenced by advice found in Sun’s own 1.4. GC tuning guides. They recommended that spaces be sized in such a way that it minimized copying. It is a recommendation that we offered until I quickly sorted out that doing just the opposite worked much better. As a sidebar, this lead to my infamous answer to a question at Sun Techdays in Johannesburg where in the Q&A section of my presentation with Dr. Heinz Kabutz I was asked for references. My answer was of course, read the Sun GC tuning guide and then do exactly the opposite. But, I digress.
Fortunately you won’t find that advice anymore in any of Sun’s documentation as we’ve now come to realize that as objects die, there are few and fewer of them to copy. Furthermore, if you give the objects longer to die, they’ll do just that. Combine that with the fact that being able to declare a whole space as being clean is so cheap that it’s just not worth the effort to avoid copying. And this is exactly what the G1 looks like it is going to do, give objects enough time to die before going in to clean out a space.
Pure speculation on my part but I also suspect that objects in one of the tenured spaces will most likely have been promoted at the same time. I also suspect that these objects will die at about the same time so that once a space starts to empty, it will become empty fairly quickly. What we do know, and this is according to Tony Printezis (author of G1) is that many tenured spaces are found to be empty during the mark phase and many more tend to have low liveliness.
This means that a lot of tenured space can be collected with little effort. It also means that spaces with high levels of liveliness will be avoided and that is a good thing also. High levels of liveliness imply very little free space which implies that the space is already compact. That means we will not waste any time moving objects, something we might do if tenured was a single contiguous space. More over, waiting to address a tenured space gives it more time and with more time one can expect to see fewer and fewer objects in it making it cheaper to collect.
I suppose there will be some pathological cases where this collector will not work. I can imagine cases where I can cause this scheme to fail. However it is my opinion that most server based applications will benefit from this new collector. Tony has been working with some standard benchmarks and beta customers and so far the results look very promising. The collector was promised for Java 7 but there are some indications that we will see it first in the 1.6. Now all you have to do is prepare for the arrival of this new low latency, more efficient collector by making sure your application is running with in the 1.6 JVM.