Java千百问_08JDK详解(013)_JVMTI是什么

版权声明:本文为博主原创文章,若需转载请写明出处,支持原创,谢谢。 https://blog.csdn.net/ooppookid/article/details/51809545

点击进入_更多_Java千百问

1、JVMTI是什么

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中得到当前的运行态信息,还可以操作虚拟机的运行态

2、如何加载JVMTI agent

当我们把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]

3、JVMTI agent是如何工作的

Agent的启动

Agent是在Java虚拟机启动时加载的,这个时间点上:

  • 所有的Java类都未被初始化
  • 所有的对象实例都未被创建
  • 所有的Java代码都没有被执行

但在这个时候,我们已经可以:

  • 操作JVMTI的Capability参数
  • 使用系统参数

通过启动加载模式加载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)

4、如何编写JVMTI agent程序

只要有一定的C++基础就可以编写JVMTI agent,具体看这里:[如何编写JVMTI agent程序][4]

阅读更多
想对作者说点什么?

博主推荐

换一批

没有更多推荐了,返回首页