

Table of Contents
1. What is Java agent?
In Java 1.5 Instrumentation API was introduced (java.lang.instrument package) to enable byte-code modification (instrumentation) of classes and to get runtime insights. This is very helpful to tool developers. In this article, we’ll see how Instrumentation API can be leveraged to determine approximate object size at runtime.
Java agent is packaged as a plain Jar containing a set of classes having some specific methods. When an application is run with a Java agent, the agent performs the required instrumentations.
2. Starting Java agent
Java agent can be started either statically or dynamically in a running JVM. To start Java agent statically, add the javaagent option while launching the application:
java -javaagent:myagent.jar org.openapex.samples.misc.instrument.ObjectSize
To start a Java agent in a running JVM, do the following:
VirtualMachine vm = VirtualMachine.attach(jvmPid); // target JVM PID vm.loadAgent(agentFile.getAbsolutePath());
3. Creating Java agent
If you plan to start the Java agent statically, then create a class with the following premain method. This method is called by the JVM to start the agent.
public class MyInstrumentationAgent {
public static void premain(String agentArgs, Instrumentation inst){
System.out.println("Set the instrumentation from premain");
// Attach class transformers
}
}
In case you plan to start the Java agent dynamically, then create a class with the following agentmain method. This method is called by the JVM to start the agent.
public class MyInstrumentationAgent {
public static void agentmain(String agentArgs, Instrumentation inst){
System.out.println("Set the instrumentation from agentmain");
// Attach class transformers
}
}
If you want to have the flexibility to start the agent both statically and dynamically, you may define both the methods in the same class.
Now, create a JAR in the usual way using jar command and ensure the following entries (Premain-class and Agent-class) are present in the manifest file.
Premain-Class: org.openapex.samples.misc.instrument.MyInstrumentationAgent Agent-Class: org.openapex.samples.misc.instrument.MyInstrumentationAgent
Create the agent JAR:
jar -cvfm myagent.jar manifest.txt org/openapex/samples/misc/instrument/MyInstrumentationAgent.class
4. Determine Object size
In the previous sections, we have seen what is Java agent and how to create one for instrumentation. Let us see how we can create a Java agent and leverage Instrumentation.getObjectSize(obj) to determine object size. Define an agent class with both premain() and agentmain() methods. Keep the reference of Instrumentation object and later use it to get the object size.
package org.openapex.samples.misc.instrument;
import java.lang.instrument.Instrumentation;
public class MyInstrumentationAgent {
private static Instrumentation instrumentation;
public static void premain(String agentArgs, Instrumentation inst){
instrumentation = inst;
System.out.println("Set the instrumentation from premain");
}
public static void premain(String agentArgs){
System.out.println("Unable to set instrumentation premain");
}
public static void agentmain(String agentArgs, Instrumentation inst){
instrumentation = inst;
System.out.println("Set the insttrumentation from agentmain");
}
public static void agentmain(String agentArgs){
System.out.println("Unable to set instrumentation agentmain");
}
public static long getObjectSize (Object object){
if (instrumentation != null){
return instrumentation.getObjectSize(object);
}
System.out.println("Unable to determine object size, instrumentation is not available");
return 0;
}
}
Let us define the application class that will determine object size. In this example, we get the approximate object size of a File, String and Integer.
package org.openapex.samples.misc.instrument;
import java.io.File;
import java.lang.instrument.Instrumentation;
public class ObjectSize {
public static void main(String[] args) {
File f = new File("data/user.csv");
String hello = "Hello World";
Integer num = Integer.valueOf(100);
System.out.println("Size of file object: " + MyInstrumentationAgent.getObjectSize(f));
System.out.println("Size of file string: " + MyInstrumentationAgent.getObjectSize(hello));
System.out.println("Size of file integer: " + MyInstrumentationAgent.getObjectSize(num));
}
}
Start the application by adding javaagent option:
java -javaagent:myagent.jar org.openapex.samples.misc.instrument.ObjectSize
Here is the output from ObjectSize application:
Size of file object (bytes): 32 Size of string (bytes): 24 Size of integer (bytes): 16
5. Byte-code modification
If you want to modify byte-code from your Java agent, create one or more ClassFileTransformer and add these to the Instrumentation object from premain() or agentmain() methods.
The ClassFileTransormer looks like:
public class MyClassTransformer implements ClassFileTransformer{
@Override
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
// Here change the byte code as needed
byte[] newbytes = new byte[100];
return newbytes;
}
}
Add the transformer to the Instrumentation object:
public static void premain(String agentArgs, Instrumentation inst){
instrumentation = inst;
System.out.println("Set the instrumentation from premain");
instrumentation.addTransformer(new MyClassTransformer());
}
6. Conclusion
In this article, we have seen how to create a simple Java agent and use it in an application. The possible uses cases of instrumentation are limitless. The source code, manifest file, agent Jar files can be downloaded from GitHub
Join our list to get instant access to new articles and weekly newsletter.

