|
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
|