A key component of any Java VM implementation is the garbage collector. As an automatically garbage collected environment, garbage collection in the JVM has a significant impact on Java application performance, as well as on the amount of memory a Java application can realistically take advantage of. Sun has shipped two garbage collectors in recent Java SE versions, including a parallel garbage collector, and the default concurrent mark-and-sweep one.
In the latest update to JDK 6, Sun introduced a new garbage collector, G1. G1 provides low-latency, soft real-time garbage collection, and is slated to eventually replace the mark-and-sweep collector as the Sun VM's default. In a recent article for Dr. Dobb's, G1: Java's Garbage First Garbage Collector, Eric Bruno describes how the G1 garbage collector can help improve application performance:
Garbage-First is a server-style garbage collector, targeted for multi-processors with large memories, that meets a soft real-time goal with high probability... It does this while also achieving high throughput, which is an important point when comparing it to other real-time collectors...
In terms of GC pause times, Sun states that G1 is sometimes better and sometimes worse than CMS. As G1 is still under development, the goal is to make G1 perform better than CMS and eventually replace it in a future version of Java SE (the current target is Java SE 7)...
While the G1 collector is successful at limiting total pause time, it's still only a soft real-time collector. In other words, it cannot guarantee that it will not impact the application threads' ability to meet its deadlines, all of the time. However, it can operate within a well-defined set of bounds that make it ideal for soft real-time systems that need to maintain high-throughput performance.
The rest of Bruno's article describes the inner workings of the G1 garbage collector.
What do you view as the biggest limitation of current JVM garbage collectors? To what extent do you think G1 will overcome those limitations?
I'm sure there will be improvements from G1, but I can't help but be reminded of my college compiler professor's comment that every gc'd language he ever worked on started with a simple gc system that got more and more complicated as they squeezed performance out of it until, finally, it fell over in a heap, and someone replaced it with another simple implementation. Wash, rinse, repeat.
Again, that's not to say that G1 won't be an improvement, and perhaps a big improvement in some cases, but just to say that, sans hardware innovations, general, large performance boosts are probably going to be difficult to come by.
and the perf results seem ambiguous. Does anyone have more recent information?
If I were a betting man, and I'm not, I'd put money on what we've seen historically: the hardware guys will keep kicking our ass at making things faster. Even so, that's no excuse to keep trying, and kudos to Soracle for keeping hope alive.
"... reminded of my college compiler professor's comment that every gc'd language he ever worked on started with a simple gc system that got more and more complicated as they squeezed performance out of it until, finally, it fell over in a heap ..."
What millennium were you in college? ;-)
The science of automated GC has truly blossomed in the past decade, so using historical precedent is dangerous.
It is also worth noting that the necessity for improvement is clear: Improvements in hardware speed and in the efficiency of traditional single-threaded algorithms for GCing a global heap cannot keep pace with the growth of memory utilization. In other words, all things equal, GC'd languages would have ultimately failed as GC times increased near-linearly with heap size.
Fortunately, all things are not equal, and the realization that most memory allocations are thread local (hence escape analysis) and short lived (hence slabbed allocators) have the ability to reduce the need for global memory GC. In most systems, the combination of these and related technologies give GC-based languages a significant performance edge over languages requiring the programmer to manage memory.
Nonetheless, the bogeyman still exists: Global heap GC. jRockit (acquired by BEA then Oracle) has a deterministic GC mode that can keep pause times below 10ms (and even lower!), but:
* Application developers still have to be careful (i.e. it's not idiot proof); specifically, the application has to limit the amount of medium- and long-lived objects that it is creating
* It requires tuning
* The amount of memory used by the application must be constrained
* It requires a significant amount of memory compared to what the application actually is using at any given time (i.e. if the app needs a few hundred MB, the heap size might have to be a GB to achieve deterministic results)
* Depending on the application profile, it may not work at all (i.e. pause times may be significantly longer than the standard Sun GC for some apps)
In other words, the current state-of-the-art GC implementations are able to "keep up" with deterministic pause times, but only with a pretty sizable set of caveats.
G1 looks like a pretty big advance for Hotspot though, and I can't wait to see what comes next ..
I'd be ok with just about any GC, but I sure wish we didn't have PermGenSpace (or rather, the errors) and I don't understand why a Java application defaults to a meager 64mb in this day and age with 4GB less than 100$.
I of course agree that the increasing dominance of Amdahl's law will require new GC implementations, but I think there's a good chance it will run into the same problems we are seeing elsewhere in parallel computing: the APIs are too hard or limited or the implementations are too complicated, or all three.
That's not to say that there won't be improvements, and G1 might be one, but it is to say that I'm skeptical that they are going to have the bang that, say, hotspot had. An interesting Proebsting-esqe wager: Starting on today's hardware and measuring some reasonable application (say a bog-standard pet store implementation) five years from now will the majority of the speed up achieved be available without G1?
Of course there are all sorts of confounding variables, but I'm not sure which side of that wager I'd take.
Just a small comment regarding short-lived objects: value-type objects can make a lot of heap-allocated short-lived objects redundant. I think Java and other languages that have only-heap allocated objects suffer from this. In my opinion, programming languages should have value objects, because they diminish the work of the GC.
> Just a small comment regarding short-lived objects: > value-type objects can make a lot of heap-allocated > short-lived objects redundant. I think Java and other > languages that have only-heap allocated objects suffer > from this. In my opinion, programming languages should > have value objects, because they diminish the work of the > GC.
I read some stuff about escape analysis in Java having the potential to stack allocated objects (actually the internal variables) without any change to the language. I'm not sure if that's been implemented.
GC work isn't just about speeding things up .. in many cases, GC advances actually cause a higher percentage of CPU time to be spent doing GC! The largest efforts in GC today are to provide more determinism in how the GC processing interrupts the normal execution of the program. (In other words, being able to ensure that GC doesn't interrupt normal execution for more than a certain number of microseconds or milliseconds at a time.)
FWIW - Regardless of the topic (GC, language, compiler, loading, runtime, network, whatever), I hear many more customer requests for predictability than I hear for speed. Today, only a few applications truly desire speed at the cost of predictability.
> Just a small comment regarding short-lived objects: > value-type objects can make a lot of heap-allocated > short-lived objects redundant. I think Java and other > languages that have only-heap allocated objects suffer > from this. In my opinion, programming languages should > have value objects, because they diminish the work of the > GC.
"Java" does not have a heap. As such, JVM implementations (most of which use a heap, among other memory management structures) have the ability to allocate storage as they deem best, including how you are describing.
> > Just a small comment regarding short-lived objects: > > value-type objects can make a lot of heap-allocated > > short-lived objects redundant. I think Java and other > > languages that have only-heap allocated objects suffer > > from this. In my opinion, programming languages should > > have value objects, because they diminish the work of > the > > GC. > > "Java" does not have a heap. As such, JVM implementations > (most of which use a heap, among other memory management > structures) have the ability to allocate storage as they > deem best, including how you are describing. > > Peace, > > Cameron Purdy | Oracle Coherence > http://coherence.oracle.com/
You mean that there is no concept of heap for the programmer. Because the VM allocates memory from the heap.
> I read some stuff about escape analysis in Java having the > potential to stack allocated objects (actually the > internal variables) without any change to the language. > I'm not sure if that's been implemented.
> You mean that there is no concept of heap for the > programmer. Because the VM allocates memory from the heap.
Exactly. In C, alloc() comes from the heap. In C++, "new" comes from the heap (with some cool possibilities of being overridden on a class by class basis, which used to be a great way to optimize performance and add conditional debugging logic).
In Java, "new" could come from a heap, or from the stack, or from a thread local slab allocator (basically, an additional stack). Or the JVM could even pre-allocate space as part of the stack frame based on runtime profiling data and escape analysis.
It is a consistent trend in programming languages: Moving away from the "exactly how to do it" to the "stating what I want done".
> You mean that there is no concept of heap for the > programmer. Because the VM allocates memory from the heap.
I think what is meant is that there is no requirement for a heap as part of the Java language. At least on some level, that's clearly true given that JVMs can optimize heap allocations out of a lot of code.
> 'Regulars' on comp.lang.c are eager to teach you > that C has no 'heap'. C++ has a 'free store' but no heap, > either.
Of course the C _language_ has no heap. At any rate, a heap is simply a data structure that's efficient for managing information about memory blocks. I'm personally unaware of C runtime library implementations that manage memory and that _don't_ use a heap for alloc(); while it's not as fun as practicing pedanticism, perhaps the regulars on comp.lang.c could find one?
> > In Java, "new" could come from a heap, or from the > > stack, or from ...
> Same in C and C++.
No, not the same in C and C++. Once compiling and linking are done in C/C++, the allocation will always use the same method. It's not a runtime decision. In a language such as Java, "new" (alloc) is not a method, nor is it bound to a class or runtime library. The JVM can cause the same "new" call in the code to allocate in a stack-based manner, using a slab allocator, or using a heap, (or in any other manner for that matter), and it can make that decision as early or as late as it chooses to.