Java Performance Services
Training, Seminars, Benchmarking, Tuning

Java Performance Tuning Course


Chania Crete, May 17-20, 2010


Sun Extreme Learning EXL-2025

Houston, December 1-4,2009
New York, December 8-11, 2009
Washington DC, January 5-8, 2010



San Francisco, January 11-14

Anti-if

I have joined Anti-IF Campaign

Calendar

««Nov 2009»»
SMTWTFS
1234
5
67
891011121314
15161718192021
22232425262728
2930

Performance Anti-Patterns

My Top Tags

                                       

Mailing List

My RSS Feeds








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.



1. anjan bacchu left...
Friday, 29 August 2008 12:15 am :: http://anjanb.wordpress.com

hi there,

  • nice tip. thank you.

  • Most Java 1.5 apps should work in Java 1.6 as well except for the issues with JAXB/JAX-WS. correct ? OR are there some compatibility issues with upgrading to 1.6 ? My experience running a few web/Swing apps over the last year tell me that almost all apps work just fine with 1.6.

BR, ~A


2. William Louth left...
Friday, 29 August 2008 7:46 pm :: http://blog.jinspired.com

There are (unmanaged) changes in the Swing codebase that do break some applications moving from 1.5 to 1.6. I am currently working on workarounds myself while preparing our management console for Java 6. Also there are changes to the runtime class initialization sequence when registering native methods which causes a few problems as well.


3. Gregg Sporar left...
Tuesday, 2 September 2008 6:07 pm :: http://blogs.sun.com/gregg

Hi Kirk. Tony's JavaOne presentation about G1 (along with Paul Ciciora from CBOE) is available online: http://developers.sun.com/learning/javaoneo nline/j1online.jsp?track=javase&yr=2008 Watching the replay requires registering with the Sun Developer Network, but that's free. :-) HTH - Gregg


4. stolsvik left...
Sunday, 14 September 2008 4:32 pm :: http://stolsvik.com/

Do you have an idea of how will this fare with lots of rather large objects, in the 10-30 MB range? The reason for asking, is that the current generational approach seems to handle this rather bad, at least in the context of a desktop app that can't easily be given 2 or more GBs of memory. I have this photo organization application where loading such multi-tens-of-MBs objects obviously is a quite common thing, given the prevalence of multimegapixel cameras of today. What seemed to happen, was that there wasn't room for such big objects in the young generation blocks at all, and they were "promoted" to the tenured gen right away (or at least very fast). Since they nevertheless are quite short-lived, and that there is a huge churn of memory as the user browses, or the system does "for-eaching" of your entire collection, this lead to the application going into full stop-the-world GCs all the time.

I ended up implementing a "good old" object pool, albeit somewhat fancy, based on requested image size (and -type). See, you tend to have a lot of pictures captured with the same camera. This results in lots of the BufferedImages being of the exact same size, which again results in a very high hit rate in the pool. I ended up with a system that use very much memory, but doesn't really have any churn at all (What happens is that given enough memory, the pool stabilizes and have BufferedImages of all your image sizes at the ready).

However, I've basically ended up implementing a kind of memory management system outside of the VM, and this bothers me: I'd rather have this handling in one place! Thus, the question is how you perceive the G1 collector would handle the above-described scenario? Btw, the following blog entry, and the ensuing comment rounds, is interesting: http://blogs.sun.com/jonthecollector/entry/our_collectors. Check out my comment/question about comparison between explicit memory management vs. garbage collection in regard to the "overhead requirements", and the comments about "bookmarking collection" for GC vs. swapping.