- 创建一个有premain方法的agent 类,
- JVM在调用agent类的premain方法时会传入一个Instrumentation 对象,调用Instrumentation的getObjectSize方法
- 把agent类打成一个jar包
- 启动我们的应用程序,使用JVM参数指定agent jar的路径
1. 创建Instrumentation agent类
1 public static void premain(String args, Instrumentation inst) {
2 ...
3 }
JVM会在应用程序运行之前调用这个方法(也就是在执行应用程序的main方法之前),JVM会在调用该方法时传入一个实现Instrumentation接口的实例,此时我们就可以调用getObjectSize()方法来计算对象的大小。例如我们要计算Object实例和自定义类型MyObject实例的大小,agent代码如下:
1 package my;
2 import java.lang.instrument.Instrumentation;
3
4
5 public class MyAgent {
6 public static void premain(String args, Instrumentation inst) {
7 Object obj = new Object();
8 System.out.println("Bytes used by Object:"+ inst.getObjectSize(obj));
9 System.out.println("Bytes used by MyObject:"+ inst.getObjectSize(new MyObject()));
10 }
11 public static void main(String[] args) {
12 System.out.println("main is over");
13 }
14 }
MyObject代码如下:
1 package my;
2
3 public class MyObject{
4 Object object = new Object();
5 }
需要注意的是agent类不需要实现任何接口,只需要定义premain方法就行,JVM会自动调用该方法。
2. 把agent类打包成jar包
Premain-Class: my.MyAgent
然后执行一下命令创建jar包
jar -cmf manifest.txt agent.jar my/*
3.使用agent运行应用程序
java -javaagent:agent.jar -cp . my.MyAgent
在32位机器上运行结果如下:
[email protected]:~/workspace/my/bin$ java -javaagent:agent.jar my.MyAgent Bytes used by Object:8 Bytes used by MyObject:16 main is over
在64位机器上(不开启指针压缩)运行结果如下:
[[email protected] ~]$ java -XX:-UseCompressedOops -javaagent:agent.jar -cp . my.MyAgent Bytes used by Object:16 Bytes used by MyObject:24 main is over
在64位机器上(开启指针压缩)运行结果如下:
[[email protected]~]$ java -XX:+UseCompressedOops -javaagent:agent.jar -cp . my.MyAgent Bytes used by Object:16 Bytes used by MyObject:16 main is over
运行结果显示对于Object对象在32bit机器上占8个字节,在64bit机器上占16个字节,而对于用于一个Object类型成员的MyObject在32bit机器上占用16个字节,而在64bit机器上不开启指针压缩是占用24个字节,开启指针压缩后占用16个字节。
在应用程序中访问Instrumentation对象
在上面的例子中,我们在premain方法中计算对象的大小。可是如果我们想要在应用程序执行期间计算某个对象的大小该怎么办呢?
我们可以这样做,在premain方法中把Instrumentation对象保存在一个static引用中,然后提供一个static方法访问这个实例,代码如下:
1 public class MyAgent {
2 private static volatile Instrumentation globalInstr;
3 public static void premain(String args, Instrumentation inst) {
4 globalInstr = inst;
5 }
6 public static long getObjectSize(Object obj) {
7 if (globalInstr == null)
8 throw new IllegalStateException("Agent not initted");
9 return globalInstr.getObjectSize(obj);
10 }
11 }
这样我们就可以在应用程序中调用 MyAgent.getObjectSize()来计算运行时任意实例的大小了。