标签:
JVMTI(JVM Tool Interface)是JPDA体系中的最底层, 由Java虚拟机提供的native编程接口,是JVMPI(Java Virtual Machine Profiler Interface)和 JVMDI(Java Virtual Machine Debug Interface)的更新版本。
了解JPDA体系看这里:JPDA是什么
从它的发展中我们就可以知道,JVMTI提供了调试(debug)和分析(profiler)功能;同时,它还有监听(Monitoring),线程分析(Thread analysis)以及覆盖率分析(Coverage Analysis)等功能。正是由于JVMTI的强大功能,它是实现Java调试器,以及其它Java运行态测试与分析工具的基础。目前已有很多成熟的集成工具提供了JVMTI的实现(例如Sun、IBM以及一些开源项目如Apache Harmony DRLVM),这些工具虽然强大易用,但是在一些特定情况下,开发者常常会有一些特殊的需求,这个时候就需要定制工具来达成目标。
JVMTI是一套本地代码接口,因此我们需要使用C/C++以及JNI。开发时一般采用建立一个Agent(通过C++编写)的方式来使用JVMTI,它可以使用JVMTI函数、设置回调函数、从JVM中得到当前的运行态信息,还可以操作虚拟机的运行态。
当我们把Agent编译成一个动态链接库之后,我们可以通过两种方式加载Agent:启动加载模式、活动加载模式。具体如下:
启动加载模式
在Java程序启动时加载它,其实是在java启动时指定加载agent,如下:
-agentlib:<agent-lib-name>=<options>
注意,这里的路径是环境变量的相对路径,例如 java -agentlib:libagent=opt,java启动时会PATH环境变量定义的路径处装载libagent.so
-agentpath:<path-to-agent>=<options>
这里是绝对路径,例如 java -agentpath:/home/admin/agentlib/libagent.so=opt
活动加载模式
Java 5之后可以在运行时加载agent,通过com.sun.tools.attach包的API来实现(需要引入${JAVA_HOME}/lib/tools.jar)。使用非常简单,如下:
public class TestAgent {
public static void main(String[] args) throws AttachNotSupportedException, IOException, AgentLoadException,
AgentInitializationException {
String pid = "831"; // 想要装载的java进程id
String agentPath = "/Users/sunjie/Desktop/libagent.so"; // agent.so的路径
String options = null;// 传入agent的参数
VirtualMachine virtualMachine = com.sun.tools.attach.VirtualMachine.attach(pid);
virtualMachine.loadAgentPath(agentPath, options);
virtualMachine.detach();
}
}
了解AttachAPI看这里:[AttachAPI是什么][3]
Agent的启动
Agent是在Java虚拟机启动时加载的,这个时间点上:
但在这个时候,我们已经可以:
通过启动加载模式加载Agent之后,虚拟机会先寻找一个Agent入口函数:
JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved)
如果是运行加载模式,则是:
JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved);
在这个函数中,虚拟机传入了一个JavaVM指针,以及命令行的参数。我们通过*jvm可以获取jvmtiEnv,即可以使用JVMTI函数,当然不同的JVM实现提供的函数细节可能不一样,但是使用的方式一致。如下:
jvmtiEnv *jvmti;
(*jvm)->GetEnv(jvm, &jvmti, JVMTI_VERSION_1_1);
这里第二个参数为版本信息,不同的JVMTI环境所提供的功能、处理方式可能有所不同,不过它在同一个虚拟机中会保持不变。
Agent的卸载
当Agent完成任务,或者JVM关闭的时候,虚拟机会调用函数来完成最后的清理任务,如下:
JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *jvm)
只要有一定的C++基础就可以编写JVMTI agent,具体看这里:[如何编写JVMTI agent程序][4]
标签:
原文地址:http://blog.csdn.net/ooppookid/article/details/51809545