JvmTI hello world
JvmTI (Jvm Tools Interface) 作为一个强大的jvm工具接口,提供很多很强大有用的功能。最近尝试下使用,简单记录下。
中文参考的是Ken Wu的博客,太具体的细节我就不累述了,这里直接解释我的hello world的过程吧。
首先需要准备一个jvm实例用于测试,为什么不选择已经在运行的象eclipse之类的大家伙,稍候介绍,我现在准备一个很简单的程序吧
public class TestMain {
public static void main(String[] args) {
System.out.println("Start to Sleep");
try {
Thread.sleep(1000 * 60 * 60);
} catch (InterruptedException e) {
//Do nothing
}
}
}
启动它
java TestMain
接下来需要写一个最简单的jvmti的agent:
#include
#include
JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *vm,
char *options, void *reserved) {
printf("On attach\n");
return (jvmtiError) 0;
}
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm) {
printf("Unload");
}
编译成共享库
JAVA_HOME=/opt/j2sdk gcc main.c -o agent.so -I $JAVA_HOME/headers -I $JAVA_HOME/include/linux --shared -fPIC -Wall
最后就是试下这个agent能不能用了,写一个java类来测试吧:
public class JvmHelloWorld {
public static void main(String[] args) throws Exception {
String pid = "1497";
String agentPath = "/data/tmp/agent.so";
VirtualMachine vm = VirtualMachine.attach(pid);
vm.loadAgentPath(agentPath);
vm.detach();
System.out.println("done");
}
}
这里写死了agent的地址和pid是为了尽可能的简单,pid就是刚才我们启动的jvm实例的进程号,可以通过jps命令帮助查找到;agentPath就是刚才编译好的库文件.
直接从eclipse里执行就可以了,看看结果吧。
测试程序JvmHelloWorld很快就返回了(如果没有报错的话),但是只输出了“done”,没有输出“On attach”。
切换到刚才启动TestMain的窗口,会发现在那里输出了“On attach”,也就是说其实agent是被作为参数传给另一个jvm,然后在已经运行的jvm(我们想获得信息的那个)里执行,这也就解释了为什么“On attach”不在JvmHelloWorld中输出了。
另外,一个jvm在重启前,对于相同的一个agent库文件(注意,这里以文件为标识)只会读取一次文件信息,但是可以多次执行,每次使用attach命令就会执行一次,但是如果我们重新编译了库文件,不会立即起效果,最好的方案是生成一个新的库文件,重新attach一次。
之前提到为什么要单独写一个TestMain而不直接查看eclipse的原因是,eclipse执行agent的输出很难看到,对于hello world来说太麻烦了。