首先提出一个问题:我们如何与JVM交互?
我想想,JDK应该是我们对接JVM的最主要手段。还有JProfiler,IBM的MAT,Jconsole的输入参数经常是dump文件,使用堆分析器或者 Dump 文件分析器等工具进行研究,查看当前运行态堆(Heap)中存在的实例整体状况来诊断问题,看起来不是不是通过JDK与JVM交互的。
基于一般的设计思路:定义一个接口,内部提供一些实现,同时对外提供一些扩展的入口,JVM作为一个系统,也有这方面的考虑,来实现一些特殊的定制(到底是什么样的定制呢?带着疑惑,我们一起在后面去寻找答案),这套机制就是JVMTI(JVM Tool Interface)。
JVMTI是 Java 虚拟机所提供的 native 编程接口。之前版本有JVMPI(Java Virtual Machine Profiler Interface)和 JVMDI(Java Virtual Machine Debug Interface)。从这个 API 的发展历史轨迹中我们就可以知道,JVMTI 提供了可用于 debug 和 profiler 的接口。同时,在虚拟机接口也增加了监听(Monitoring),线程分析(Thread analysis)以及覆盖率分析(Coverage Analysis)等功能(Java 5/6 中增加)。正是由于 JVMTI 的这些特性,基于它,实现了 Java 调试器,以及其它 Java 运行态测试与分析工具。
注意⚠️:JVMTI 并不一定在所有的 Java 虚拟机上都有实现,不同的虚拟机的实现也不尽相同。不过在一些主流的虚拟机中,比如 Sun 和 IBM,以及一些开源的如 Apache Harmony DRLVM 中,都提供了标准 JVMTI 实现。
刚才说的有点抽象,具体如何落地呢?怎么去实现自己的定制呢?
JVMTI是一套本地代码接口,因此使用JVMTI需要与C/C++以及JNI打交道。开发时一般采用简历一个Agent的方式来使用JVMTI,agent使用JVMTI函数,设置一些回调函数,从JVM中获取当前的运行态信息,需要的时候,可能去修改JVM的运行态(JVM提供了的入口)。因为使用的是C/C++,所以agent一般会编译成一个动态链接库来使用。JAVA体系的一种生效方式是在程序启动的时候来加载它(启动加载模式),还有一种运行时加载模式(1.5后提供,活动加载模式)。具体的配置参数如下:
-agentlib:agent-lib-name=options
-agentpath:path-to-agent=options
Agent 即 JVMTI 的客户端(对外而言,更像JVM提供的API),它和执行 Java 程序的虚拟机运行在同一个进程上,因此通常他们的实现都很紧凑,他们通常由另一个独立的进程控制,充当这个独立进程和当前虚拟机之间的中介,通过调用 JVMTI 提供的接口和虚拟机交互,负责获取并返回当前虚拟机的状态或者转发控制命令。
网友评论