9 Nov 2008

In JIT we trust

I remember a debate with a colleague five years ago about the merits of dynamic compilation versus static compilation. He was arguing that .NET was ‘better’ than Java because .NET had an ngen utility for AOT native code generation. Of course, he favoured straight C++ even more because it was unmanaged; he felt that the management in managed systems just slowed things down.

I disagreed strongly with him at the time, citing the capabilities of the JIT compiler in Java at the time (it was at 1.4 back in those days, if I remember right; right about the time when there was that big fight between log4j versus java.util.logging). Well, of course, it's improved a lot since then, and I'm especially happy with the capabilities of Java 6 in the performance department!

John Rose (the mastermind behind the Da Vinci Machine project) has a page detailing all the various optimisations currently in place in Hotspot; there are sure to be even more optimisations for dynamic code invocation to come up.


On a related topic, I was perusing the OpenJDK 6 code today, and I learnt about a really cool technique they use in reflection (yes, I'm aware that the technique was implemented even in the 1.4 days, but OpenJDK code is easier to obtain, so that's what I'm looking at). Now, assuming that you, the reader, are not an expert in Java's core library implementation, how would you go about implementing reflection? Have a think about it, then read on (if you want to).

If you've played with JNI at all, I would presume you'd probably be thinking of that. Just write a native method that simply calls the JNI's builtin reflection functionality (or some shortcut thereto in the JVM). This, indeed, does work, and is one way that OpenJDK 6 does it.

It has a much cooler technique, though, called “inflation”. Inflation means that for the first few runs (default 15) of a reflected method/constructor (from now on, any reference to methods applies to constructors too), it does so via JNI; the next time after that, it assembles a class file on the fly, and loads it. At that point, full JITting applies, and further calls to that reflected method has the same performance as directly calling that method.

You can even disable inflation completely (set the sun.reflect.noInflation property to true), in which case the JNI approach is skipped completely, and all reflected method calls are assembled to class files straight away. Alternatively, you can tune the number of runs before the assembly occurs (use the sun.reflect.inflationThreshold property).

If that's not cool, I don't know what is!

5 comments:

Unknown said...

In fact, both GCJ and Excelsior JET existed five years ago. :) Today, the latter is certified Java SE 6 compatible and uses the licensed Sun's implementation of the standard API.

The Ferret's Sidekick said...

Thanks for the links! I'm still more in favour of dynamic compilation, but if I run into my former colleague again, and if he still holds the same views about static vs dynamic compilation, I'll be sure to pass those links onto him. :-)

Unknown said...

The choice surely depends on your needs and on the nature of your application. For instance, custom classloaders in the general case hinder AOT compilation.

Just in case, I have written about the pros and cons of AOT compilation in this article. Here are a few sample apps illustrating one of the benefits.

b0b0b0b said...

word of caution, noInflation=true will eagerly assemble the generated class bytecode. totally counterintuitive.

anshuiitk said...

Stumled upon this post .. just to mention that I recently wrote an article around this explaining how it could lead to memory problems. Its is at http://anshuiitk.blogspot.com/2010/11/excessive-full-garbage-collection.html