PoP Some notes on using java.lang.instrument
Other Options

In a nutshell

Examples

Links

New with version 1.5 of the JVM comes a profiling interface that simpler and cleaner than anything that's been available so far: it's called java.lang.instrument.

First, some other options

We've been working on the static and dynamic analysis of Java programs for some time, and have tried numerous options:
  • Instrumenting an open-source JVM - we've used Kaffe and the JamVM. This gives you complete control, but involves some messing around with low-level interpreter internals. There can also be compatibility issues, since most of the open-source JVMs use GNU classpath rather then the standard SUN libraries.
  • I should probably mention some of the larger research JVMs that were design with experimentation in mind: the Jikes RVM (originally from IBM), the Sable VM, and Intel's ORP.
  • Bytecode instrumentation - we've used BCEL, but there are other options. These give you fairly good control (at the cost of fiddling with bytecode), but can lead to code bloat if you're instrumenting the same file for different purposes (lots of versions).
  • In a similar vein, you could avoid bytecode altogether and use Aspect-Oriented programming (such as AspectJ). We've kept at the bytecode level since it delivers nice fine-grained control: it suits us to take a bytecode instruction as the basic atomic unit of analysis.
  • Earlier (pre-1.5) versions of the JVM supported the JVM Profiler Interface that allowed you to hook in your (native) code to the JVM, which would then get notified with events such as method calls and object allocation. This works fine, provided you're happy with the kinds of events being notified.
To cut a long story short, we've come around to using java.lang.instrument as offering us the level of granularity we like (bytecode), and the opportunity to use BCEL, without the messy business of having to prepare and maintain instrumented versions of the code.

java.lang.instrument in a nutshell (really)

Basically, the java.lang.instrument interface lets you write a handler that is loaded when the JVM is run and, as each other class is loaded, it is passed to your handler. You can thus analyse or instrument the class as it's loaded - or ignore it, of course.

The handler is written in Java, and gets passed a bytecode array - just the sort of thing that libraries such as BCEL are set up to handle (and to make simple for you).

Examples

I've done up some examples of using java.lang.instrument, based on the code mentioned below and a few other bits and pieces that we've been doing here.

  • A trivially simple example - these are the ones I like to start with. This example does nothing other than print out the very basics of what's going on, but serves as a foundation for all the other examples.
    Code
  • A slightly less-simple example that uses BCEL to print out information about the fields in a class
    Code
  • This example tries to put together a simple class diagram, and uses the dot tool to display the output. Even if you don't have dot, it should be easy to change this to a format you like; if you do have dot, then you can produce nice colourful diagrams.
    Code
  • The last example goes a little further, and uses BCEL to instrument the code so that when the code is run it generates some information about what's going on. This example prints out information about object creation and deletion as well as field assignments
    Code

To use these, just edit the Makefile in each directory to set up the classpath for BCEL and regexp.

There are some trivial examples that can be run by typing make run (these expect the test inputs to be in ../testCases relative to the code).

I know, I know - I should be using Ant rather than Makefiles. I'll get there eventually (besides, I've gotten to like wrinkles).

The last example above forms the basis for the analysis in our VLHCC paper on visualising the Java heap.

Links

  • You'll need to check your JDK documentation for information on the java.lang.instrument package itself; for example, the documentation from version 1.5
  • Our examples are elaborations of the code from the blog at BadMagicNumber
  • Another example (uses ASM instead of BCEL) is available from Inigo Surguy
  • A BCEL-using example is explained at OnJava

James Power,
Dept. of Computer Science, NUI Maynooth
Last revised: 18 October 2005