Java Profiling: Under the Covers
Intercepting bytecode
You probably noticed the unused Instrumentation parameter from our premain method above. When the Java runtime hands you an instance of an Instrumentation, you are provided the hook you need to provide your own ClassFileTransformer. ClassFileTransformer is an interface with a single method -- transform. It is in this transform method that you will get the opportunity to intercept the class bytecodes and instrument it or not, as you choose.
Next, we'll save the passed-in Instrumentation instance, create a ClassFileTransformer, and pass it to the Instrumentation instance. Below is an example:
package com.example.profiler;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.security.ProtectionDomain;
public class Profiler implements ClassFileTransformer
{
protected Instrumentation instrumentation = null;
public static void premain(String agentArgs, Instrumentation inst)
{
System.out.println("premain");
Profiler profiler = new Profiler(inst);
}
public Profiler(Instrumentation inst)
{
instrumentation = inst;
instrumentation.addTransformer(this);
}
public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined,
ProtectionDomain protectionDomain, byte[] classfileBuffer)
throws IllegalClassFormatException
{
System.out.println("transform(" + className + ") (" + classfileBuffer.length + " bytes)");
return null;
}
}
Note that at this point we simply print the name and the size of the class passed to our transform method. Also note the Javadocs state that the method should return null if it chooses not to transform the class (returning the original classbyte array works, too). If I launch a simple "Hello, world!" program with this agent, I will see the following output:
premain
transform(HelloWorld) (1173 bytes)
Hello, world!
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)






Comments
Eric Meallier replied on Tue, 2009/12/08 - 6:13am
hard to get this working !
during the instrumentation, a RuntimeException was throwed by getMethods() call. The problem comes from the naming convention of the classes.
The classname given by transform is like this test/Test. The classpool understand this syntax but store test.Test. When you are looking for the class (getClass() just before getMethods) the class is lazy loaded (the byte code is not introscepted) but is not good. the problem only appear when the getMethods is called.
A workaround is to call classPool.get(className.replace('/', '.'));
Thanks for the article.
Victor Tsoukanov replied on Fri, 2010/02/19 - 1:14am