引入:
我们先从最重要的通信层讲起。通信层(JDWP) ,它的全称是Java Debug Wire Protocol。从"Wire"这词就可以看出,它主要是起到"连线”的作用,也就是说,它主要是起到把最靠近程序员的JDI(也就是调试器)和最靠近运行在虚拟机中的程序的JVMTI 连接在一起。因为彼此之间语言不通。比如说JDI这层,我们主要用的eclipse,它是JAVA语言编写的。而JVMTI是用来查询虚拟机状态的,而JAVA虚拟机是用C/C++写的,所以在语言不通的情况下,就必须有个中间过程来充当翻译。 这样就产生了 Agent 这个职位。它就是用来把从JDI发来的数据包双向转换到JVMTI对虚拟机的函数调用。
实践:
我们这里先来看下JDWP的Agent.
当明白了代理的作用后,我们来找JDWP的实现。在Sun的JDK中,我们找到了一个DLL文件叫jdwp.dll (Linux环境则是jdwp.so) . 它位于 $JAVA_HOME/jre/bin目录下。我们用exeScope软件打开查看内容:
显然,它是Oracle的Sun的JDK提供的jdwp ,它提供了2个方法,一个是_Agent_OnLoad(),一个是_Agent_OnUnload()
这两个接口是用来和JVM交互用的。其中当代理被JVM加载时,会调用_Agent_Onload方法,而代理被JVM卸载时候,会调用_Agent_OnUnLoad方法。
因为我们在远程调试时候启动JVM时候加了代理参数:
java -agentlib:<agentLibName> ,而agentLibName我们配置的是jdwp, 所以它就对应上jdwp.dll.
也就是远程调试时候自动会在启动target VM时候启用jdwp这个代理库。
总结:
从上过程我们似乎可以总结一些结论:
1. Agent 是在虚拟机启动之时加载的,这个加载处于虚拟机初始化的早期.在这个时间点上:
所有的 Java 类都未被初始化;所有的对象实例都未被创建; 因而,没有任何 Java 代码被执行;
(从这点上说,最明显的好处就是它能完成早期调试中用System.out.println()无法解决的问题,因为System.out.println()前提是代码行所在的类已经被初始化过了)
2.但在这个时候,我们已经可以:
操作 JVMTI 的 Capability 参数; 使用系统参数; 动态库被加载之后,虚拟机会先寻找一个 Agent 入口函数.