2 qq 24592567 qq_24592567 于 2015.05.26 20:55 提问

eclipse启动项目时遇到问题,报错!

FATAL ERROR in native method: JDWP No transports initialized, jvmtiError=AGENT_ERROR_TRANSPORT_INIT(197)
ERROR: transport error 202: connect failed: Connection timed out
ERROR: JDWP Transport dt_socket failed to initialize, TRANSPORT_INIT(510)
JDWP exit error AGENT_ERROR_TRANSPORT_INIT(197): No transports initialized [debugInit.c:750]
eclipse启动项目的时候报上面的错误怎么回事???

5个回答

diaoliwei2
diaoliwei2   Rxr 2015.05.26 21:02
tongyi55555
tongyi55555   2015.05.26 21:42

遇到问题想到CSDN也挺好,最好的还是自己搜索下,效率会提高很多。

baidu_28491061
baidu_28491061   2015.05.27 10:43

解决:在一个论坛上看到有高手说MyEclipse在debug的时候要调用cmd和net的。我于是试了下cmd,发现打不开了。

        继续按照cmd打不开进行搜索,发现打开cmd的方法:

转自:http://www.deepin.org/thread-2012790-1-1.html

中的“apollo_re2”的回帖 :

1.[HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\System\DisableCMD]
背景:“命令提示符已被系统管理员停用”遇到过吧? 很多病毒就是这样禁用 CMD 的。
用法:这是一个类型为 REG_DWORD 的键值
当没有这个值时,CMD 能用
当数据为 1 或 2 时,打开 CMD 就会提示“命令提示符已被系统管理员停用”
其数据为其他数字时,CMD 也可用
解决:在注册表编辑器(regedit.exe)找到这个项,把它删掉即可
命令行:reg delete "HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\System" /v "DisableCMD" /f(当然啦,你的 CMD 既然被影像劫持,又怎样打开 CMD 呢?在“运行”输入此命令即可)
2.[HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\AutoRun]
[HKEY_CURRENT_USER\Software\Microsoft\Command Processor\AutoRun]
背景:这是 CMD 的自启动项,打开 CMD 和批处理脚本时,CMD 会先检查这两个键值的数据,如果其中一个或两个都存在,这两个键值的数据会先被执行。 有的病毒就是把这个值设为自己的路径,使得用户打开 CMD 前,就现运行病毒体。
用法:这是一个类型为 REG_SZ 的键值,只要数据为一个或多个有效命令就可以了
CMD 会先检查 HKLM,然后是 HKCU
解决:每次运行 CMD 时不要直接双击,也不要在命令行上直接打上 cmd,而是加上一个 /d 的参数,CMD 则不会检查这两个键值在注册表编辑器(regedit.exe)找到这两个键值,把它的值设为空,也可以把它删掉
命令行:reg delete "HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor" /v "AutoRun" /f
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v "AutoRun" /f
3.[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\cmd.exe\debugger]
背景:影像劫持技术,相信大家都已经听过... 那是 AV 终结者的时代,它让用户打开杀软时,却打开了病毒体, 既然杀软也可以劫持,一个小小的 CMD 又有何难度?
用法:这是一个类型为 REG_SZ 的键值,只要数据为任意一行字符串(不是空字符就可以了),就可以让别人打不开 CMD,而是弹出找不到 CMD.EXE 之类的提示, PS:如果数据为一个有效的文件路径,则打开 CMD 时就会打开这个文件
解决:在注册表编辑器(regedit.exe)找到这个项,把它删掉即可

命令行:reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\cmd.exe" /f 

问题原因:
该故障是JVM远程debug存在的缺陷,只有在开启远程debug端口时才会出现;原因是由于接收到不符合JDWP协议的数据包,导致JVM崩溃。
该问题早已确认为JDK的一个bug,具体见6339385:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6339385 中的描述;
要确认系统中是否存在该漏洞,可以检查java启动参数中是否有如下相关配置:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8787
或者-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8787
若存在相关配置,那就说明java启动了远程调试端口,就会存在该漏洞;此时JVM虚拟机作为调试的服务提供端,通过8787端口监听一个连接,而调试器通过该连接与虚拟机进行交互。
目前,Windows平台的JVM提供了两种方式的连接:共享内存和 Socket连接,共享内存的服务提供端和调试端只能位于同一台机,而Socket连接则支持不同异机调试,即远程调试。
关于jdwp的参数列表详见官方文档:http://download-llnw.oracle.com/javase/1.5.0/docs/guide/jpda/conninv.html#Invocation
从官方文档中摘录几个配置事例:
-Xrunjdwp:transport=dt_socket,server=y,address=8000
在8000端口监听Socket连接,挂起VM(suspend默认为y)并且不加载运行主函数直到调试请求到达
-Xrunjdwp:transport=dt_shmem,server=y,suspend=n
选择一个可用的共享内存(因为没有指定address)并监听该内存连接,同时加载运行主函数,不挂起VM
-Xrunjdwp:transport=dt_socket,address=myhost:8000
连接到myhost:8000提供的调试服务(server=n,以调试客户端存在),挂起VM并且不加载运行主函数
-Xrunjdwp:transport=dt_shmem,address=mysharedmemory
通过共享内存的方式连接到调试服务,挂起VM并且不加载运行主函数
-Xrunjdwp:transport=dt_socket,server=y,address=8000,onthrow=java.io.IOException,launch=/usr/local/bin/debugstub
等待java.io.IOException被抛出,然后挂起VM并监听8000端口连接,在接到调试请求后以命令/usr/local/bin/debugstub dt_socket myhost:8000执行
-Xrunjdwp:transport=dt_shmem,server=y,onuncaught=y,launch=d:/bin/debugstub.exe
等待一个RuntimeException被抛出,然后挂起VM并监听一个可用的共享内存,在接到调试请求后以命令d:/bin/debugstub.exe dt_shmem

执行, 是可用的共享内存

问题解决:
应该说该问题并不算太严重,因为一般线上运行的应用都不会开启远程Debug模式,各应用服务器的默认配置也是不开启的,就算开启了该debug端口也会有防火墙保护,外网访问不到。
彻底解决该问题的方法有两种,任选其一即可:
1、在JDK1.5环境下关闭远程调试模式,开发测试环境下无所谓,但线上环境的部署脚本一定要仔细review才行;
2、升级JDK到1.6b49以上版本,这就要看应用的兼容性了,一般来说不会有什么问题;

再往前试试:深入Java调试体系JPDA(Java Platform Debugger Architecture)
对于Java虚拟机接口熟悉的人来说,您一定还记得Java提供了两个接口体系,JVMPI(Java Virtual Machine Profiler Interface)和 JVMDI(Java Virtual Machine Debug Interface),而它们,以及在 Java SE 5 中准备代替它们的 JVMTI(Java Virtual Machine Tool Interface),都是 Java 平台调试体系(Java Platform Debugger Architecture,JPDA)的重要组成部分。 Java SE 自 1.2.2 版就开始推出 Java 平台调试体系结构(JPDA)工具集,而从 JDK 1.3.x 开始,Java SDK 就提供了对 Java 平台调试体系结构的直接支持。顾名思义,这个体系为开发人员提供了一整套用于调试 Java 程序的 API,是一套用于开发 Java 调试工具的接口和协议。本质上说,它是我们通向虚拟机,考察虚拟机运行态的一个通道,一套工具。理解这一点对于学习 JPDA 非常重要。
换句话说,通过 JPDA 这套接口,我们就可以开发自己的调试工具。通过这些 JPDA 提供的接口和协议,调试器开发人员就能根据特定开发者的需求,扩展定制 Java 调试应用程序,开发出吸引开发人员使用的调试工具。前面我们提到的 IDE 调试工具都是基于 JPDA 体系开发的,区别仅仅在于它们可能提供了不同的图形界面、具有一些不同的自定义功能。另外,我们要注意的是,JPDA 是一套标准,任何的 JDK 实现都必须完成这个标准,因此,通过 JPDA 开发出来的调试工具先天具有跨平台、不依赖虚拟机实现、JDK 版本无关等移植优点,因此大部分的调试工具都是基于这个体系的。

JPDA 组成模块
JPDA 定义了一个完整独立的体系,它由三个相对独立的层次共同组成,而且规定了它们三者之间的交互方式,或者说定义了它们通信的接口。这三个层次由低到高分别是 Java 虚拟机工具接口(JVMTI),Java 调试线协议(JDWP)以及 Java 调试接口(JDI)。这三个模块把调试过程分解成几个很自然的概念:调试者(debugger)和被调试者(debuggee),以及他们中间的通信器。被调试者运行于我们想调试的 Java 虚拟机之上,它可以通过 JVMTI 这个标准接口,监控当前虚拟机的信息;调试者定义了用户可使用的调试接口,通过这些接口,用户可以对被调试虚拟机发送调试命令,同时调试者接受并显示调试结果。在调试者和被调试着之间,调试命令和调试结果,都是通过 JDWP 的通讯协议传输的。所有的命令被封装成 JDWP 命令包,通过传输层发送给被调试者,被调试者接收到 JDWP 命令包后,解析这个命令并转化为 JVMTI 的调用,在被调试者上运行。类似的,JVMTI 的运行结果,被格式化成 JDWP 数据包,发送给调试者并返回给 JDI 调用。而调试器开发人员就是通过 JDI 得到数据,发出指令。下图就展示了三者间的交互过程:

下面就简单介绍下这三个模块的主要功能:

Java 虚拟机工具接口(JVMTI)
JVMTI(Java Virtual Machine Tool Interface)即指 Java 虚拟机工具接口,它是一套由虚拟机直接提供的 native 接口,它处于整个 JPDA 体系的最底层,所有调试功能本质上都需要通过 JVMTI 来提供。通过这些接口,开发人员不仅调试在该虚拟机上运行的 Java 程序,还能查看它们运行的状态,设置回调函数,控制某些环境变量,从而优化程序性能。我们知道,JVMTI 的前身是 JVMDI 和 JVMPI,它们原来分别被用于提供调试 Java 程序以及 Java 程序调节性能的功能。在 J2SE 5.0 之后 JDK 取代了 JVMDI 和 JVMPI 这两套接口,JVMDI 在最新的 Java SE 6 中已经不提供支持,而 JVMPI 也计划在 Java SE 7 后被彻底取代。

Java 调试交互协议(JDWP)
JDWP(Java Debug Wire Protocol)是一个为 Java 调试而设计的一个通讯交互协议,它定义了调试器和被调试程序之间传递的信息的格式。在 JPDA 体系中,作为前端(front-end)的调试者(debugger)进程和后端(back-end)的被调试程序(debuggee)进程之间的交互数据的格式就是由 JDWP 来描述的,它详细完整地定义了请求命令、回应数据和错误代码,保证了前端和后端的 JVMTI 和 JDI 的通信通畅。比如在 Sun 公司提供的实现中,它提供了一个名为 jdwp.dll(jdwp.so)的动态链接库文件,这个动态库文件实现了一个 Agent,它会负责解析前端发出的请求或者命令,并将其转化为 JVMTI 调用,然后将 JVMTI 函数的返回值封装成 JDWP 数据发还给后端。
另外,这里需要注意的是 JDWP 本身并不包括传输层的实现,传输层需要独立实现,但是 JDWP 包括了和传输层交互的严格的定义,就是说,JDWP 协议虽然不规定我们是通过 EMS 还是快递运送货物的,但是它规定了我们传送的货物的摆放的方式。在 Sun 公司提供的 JDK 中,在传输层上,它提供了 socket 方式,以及在 Windows 上的 shared memory 方式。当然,传输层本身无非就是本机内进程间通信方式和远端通信方式,用户有兴趣也可以按 JDWP 的标准自己实现。

Java 调试接口(JDI)
JDI(Java Debug Interface)是三个模块中最高层的接口,在多数的 JDK 中,它是由 Java 语言实现的。 JDI 由针对前端定义的接口组成,通过它,调试工具开发人员就能通过前端虚拟机上的调试器来远程操控后端虚拟机上被调试程序的运行,JDI 不仅能帮助开发人员格式化 JDWP 数据,而且还能为 JDWP 数据传输提供队列、缓存等优化服务。从理论上说,开发人员只需使用 JDWP 和 JVMTI 即可支持跨平台的远程调试,但是直接编写 JDWP 程序费时费力,而且效率不高。因此基于 Java 的 JDI 层的引入,简化了操作,提高了开发人员开发调试程序的效率。
如下就总结了三个模块的不同点:

Java 调试接口的特点
Java 语言是第一个使用虚拟机概念的流行的编程语言,正是因为虚拟机的存在,使很多事情变得简单而轻松,掌握了虚拟机,就掌握了内存分配、线程管理、即时优化等等运行态。同样的,Java 调试的本质,就是和虚拟机打交道,通过操作虚拟机来达到观察调试我们自己代码的目的。这个特点决定了 Java 调试接口和以前其他编程语言的巨大区别。
以 C/C++ 的调试为例,目前比较流行的调试工具是 GDB 和微软的 Visual Studio 自带的 debugger,在这种 debugger 中,首先,我们必须编译一个“ debug ”模式的程序,这个会比实际的 release 模式程序大很多。其次,在调试过程中,debugger 将会深层接入程序的运行,掌握和控制运行态的一些信息,并将这些信息及时返回。这种介入对运行的效率和内存占用都有一定的需求。基于这些需求,这些 Debugger 本身事实上是提供了,或者说,创建和管理了一个运行态,因此他们的程序算法比较复杂,个头都比较大。对于远端的调试,GDB 也没有很好的默认实现,当然,C/C++ 在这方面也没有特别大的需求。
而 Java 则不同,由于 Java 的运行态已经被虚拟机所很好地管理,因此作为 Java 的 Debugger 无需再自己创造一个可控的运行态,而仅仅需要去操作虚拟机就可以了。 Java 的 JPDA 就是一套为调试和优化服务的虚拟机的操作工具,其中,JVMTI 是整合在虚拟机中的接口,JDWP 是一个通讯层,而 JDI 是前端为开发人员准备好的工具和运行库。
从构架上说,我们可以把 JPDA 看作成是一个 C/S 体系结构的应用,在这个构架下,我们可以方便地通过网络,在任意的地点调试另外一个虚拟机上的程序,这个就很好地解决了部署和测试的问题,尤其满足解决了很多网络时代中的开发应用的需求。前端和后端的分离,也方便用户开发适合于自己的调试工具。
从效率上看,由于 Java 程序本身就是编译成字节码,运行在虚拟机上的,因此调试前后的程序、内存占用都不会有大变化(仅仅是启动一个 JDWP 所需要的内存),任意程度都可以很好地调试,非常方便。而 JPDA 构架下的几个组成部分,JDWP 和 JDI 都比较小,主要的工作可以让虚拟机自己完成。
从灵活性上,Java 调试工具是建立在强大的虚拟机上的,因此,很多前沿的应用,比如动态编译运行,字节码的实时替换等等,都可以通过对虚拟机的改进而得到实现。随着虚拟机技术的逐步发展和深入,各种不同种类,不同应用领域中虚拟机的出现,各种强大的功能的加入,给我们的调试工具也带来很多新的应用。
总而言之,一个先天的,可控的运行态给 Java 的调试工作,给 Java 调试接口带来了极大的优势和便利。通过 JPDA 这个标准,我们可以从虚拟机中得到我们所需要的信息,完成我们所希望的操作,更好地开发我们的程序。

baidu_28491061
baidu_28491061   2015.05.27 10:44

解决:在一个论坛上看到有高手说MyEclipse在debug的时候要调用cmd和net的。我于是试了下cmd,发现打不开了。

        继续按照cmd打不开进行搜索,发现打开cmd的方法:

转自:http://www.deepin.org/thread-2012790-1-1.html

中的“apollo_re2”的回帖 :

1.[HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\System\DisableCMD]
背景:“命令提示符已被系统管理员停用”遇到过吧? 很多病毒就是这样禁用 CMD 的。
用法:这是一个类型为 REG_DWORD 的键值
当没有这个值时,CMD 能用
当数据为 1 或 2 时,打开 CMD 就会提示“命令提示符已被系统管理员停用”
其数据为其他数字时,CMD 也可用
解决:在注册表编辑器(regedit.exe)找到这个项,把它删掉即可
命令行:reg delete "HKEY_CURRENT_USER\Software\Policies\Microsoft\Windows\System" /v "DisableCMD" /f(当然啦,你的 CMD 既然被影像劫持,又怎样打开 CMD 呢?在“运行”输入此命令即可)
2.[HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\AutoRun]
[HKEY_CURRENT_USER\Software\Microsoft\Command Processor\AutoRun]
背景:这是 CMD 的自启动项,打开 CMD 和批处理脚本时,CMD 会先检查这两个键值的数据,如果其中一个或两个都存在,这两个键值的数据会先被执行。 有的病毒就是把这个值设为自己的路径,使得用户打开 CMD 前,就现运行病毒体。
用法:这是一个类型为 REG_SZ 的键值,只要数据为一个或多个有效命令就可以了
CMD 会先检查 HKLM,然后是 HKCU
解决:每次运行 CMD 时不要直接双击,也不要在命令行上直接打上 cmd,而是加上一个 /d 的参数,CMD 则不会检查这两个键值在注册表编辑器(regedit.exe)找到这两个键值,把它的值设为空,也可以把它删掉
命令行:reg delete "HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor" /v "AutoRun" /f
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v "AutoRun" /f
3.[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\cmd.exe\debugger]
背景:影像劫持技术,相信大家都已经听过... 那是 AV 终结者的时代,它让用户打开杀软时,却打开了病毒体, 既然杀软也可以劫持,一个小小的 CMD 又有何难度?
用法:这是一个类型为 REG_SZ 的键值,只要数据为任意一行字符串(不是空字符就可以了),就可以让别人打不开 CMD,而是弹出找不到 CMD.EXE 之类的提示, PS:如果数据为一个有效的文件路径,则打开 CMD 时就会打开这个文件
解决:在注册表编辑器(regedit.exe)找到这个项,把它删掉即可

命令行:reg delete "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\cmd.exe" /f 

问题原因:
该故障是JVM远程debug存在的缺陷,只有在开启远程debug端口时才会出现;原因是由于接收到不符合JDWP协议的数据包,导致JVM崩溃。
该问题早已确认为JDK的一个bug,具体见6339385:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6339385 中的描述;
要确认系统中是否存在该漏洞,可以检查java启动参数中是否有如下相关配置:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8787
或者-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8787
若存在相关配置,那就说明java启动了远程调试端口,就会存在该漏洞;此时JVM虚拟机作为调试的服务提供端,通过8787端口监听一个连接,而调试器通过该连接与虚拟机进行交互。
目前,Windows平台的JVM提供了两种方式的连接:共享内存和 Socket连接,共享内存的服务提供端和调试端只能位于同一台机,而Socket连接则支持不同异机调试,即远程调试。
关于jdwp的参数列表详见官方文档:http://download-llnw.oracle.com/javase/1.5.0/docs/guide/jpda/conninv.html#Invocation
从官方文档中摘录几个配置事例:
-Xrunjdwp:transport=dt_socket,server=y,address=8000
在8000端口监听Socket连接,挂起VM(suspend默认为y)并且不加载运行主函数直到调试请求到达
-Xrunjdwp:transport=dt_shmem,server=y,suspend=n
选择一个可用的共享内存(因为没有指定address)并监听该内存连接,同时加载运行主函数,不挂起VM
-Xrunjdwp:transport=dt_socket,address=myhost:8000
连接到myhost:8000提供的调试服务(server=n,以调试客户端存在),挂起VM并且不加载运行主函数
-Xrunjdwp:transport=dt_shmem,address=mysharedmemory
通过共享内存的方式连接到调试服务,挂起VM并且不加载运行主函数
-Xrunjdwp:transport=dt_socket,server=y,address=8000,onthrow=java.io.IOException,launch=/usr/local/bin/debugstub
等待java.io.IOException被抛出,然后挂起VM并监听8000端口连接,在接到调试请求后以命令/usr/local/bin/debugstub dt_socket myhost:8000执行
-Xrunjdwp:transport=dt_shmem,server=y,onuncaught=y,launch=d:/bin/debugstub.exe
等待一个RuntimeException被抛出,然后挂起VM并监听一个可用的共享内存,在接到调试请求后以命令d:/bin/debugstub.exe dt_shmem

执行, 是可用的共享内存

问题解决:
应该说该问题并不算太严重,因为一般线上运行的应用都不会开启远程Debug模式,各应用服务器的默认配置也是不开启的,就算开启了该debug端口也会有防火墙保护,外网访问不到。
彻底解决该问题的方法有两种,任选其一即可:
1、在JDK1.5环境下关闭远程调试模式,开发测试环境下无所谓,但线上环境的部署脚本一定要仔细review才行;
2、升级JDK到1.6b49以上版本,这就要看应用的兼容性了,一般来说不会有什么问题;

再往前试试:深入Java调试体系JPDA(Java Platform Debugger Architecture)
对于Java虚拟机接口熟悉的人来说,您一定还记得Java提供了两个接口体系,JVMPI(Java Virtual Machine Profiler Interface)和 JVMDI(Java Virtual Machine Debug Interface),而它们,以及在 Java SE 5 中准备代替它们的 JVMTI(Java Virtual Machine Tool Interface),都是 Java 平台调试体系(Java Platform Debugger Architecture,JPDA)的重要组成部分。 Java SE 自 1.2.2 版就开始推出 Java 平台调试体系结构(JPDA)工具集,而从 JDK 1.3.x 开始,Java SDK 就提供了对 Java 平台调试体系结构的直接支持。顾名思义,这个体系为开发人员提供了一整套用于调试 Java 程序的 API,是一套用于开发 Java 调试工具的接口和协议。本质上说,它是我们通向虚拟机,考察虚拟机运行态的一个通道,一套工具。理解这一点对于学习 JPDA 非常重要。
换句话说,通过 JPDA 这套接口,我们就可以开发自己的调试工具。通过这些 JPDA 提供的接口和协议,调试器开发人员就能根据特定开发者的需求,扩展定制 Java 调试应用程序,开发出吸引开发人员使用的调试工具。前面我们提到的 IDE 调试工具都是基于 JPDA 体系开发的,区别仅仅在于它们可能提供了不同的图形界面、具有一些不同的自定义功能。另外,我们要注意的是,JPDA 是一套标准,任何的 JDK 实现都必须完成这个标准,因此,通过 JPDA 开发出来的调试工具先天具有跨平台、不依赖虚拟机实现、JDK 版本无关等移植优点,因此大部分的调试工具都是基于这个体系的。

JPDA 组成模块
JPDA 定义了一个完整独立的体系,它由三个相对独立的层次共同组成,而且规定了它们三者之间的交互方式,或者说定义了它们通信的接口。这三个层次由低到高分别是 Java 虚拟机工具接口(JVMTI),Java 调试线协议(JDWP)以及 Java 调试接口(JDI)。这三个模块把调试过程分解成几个很自然的概念:调试者(debugger)和被调试者(debuggee),以及他们中间的通信器。被调试者运行于我们想调试的 Java 虚拟机之上,它可以通过 JVMTI 这个标准接口,监控当前虚拟机的信息;调试者定义了用户可使用的调试接口,通过这些接口,用户可以对被调试虚拟机发送调试命令,同时调试者接受并显示调试结果。在调试者和被调试着之间,调试命令和调试结果,都是通过 JDWP 的通讯协议传输的。所有的命令被封装成 JDWP 命令包,通过传输层发送给被调试者,被调试者接收到 JDWP 命令包后,解析这个命令并转化为 JVMTI 的调用,在被调试者上运行。类似的,JVMTI 的运行结果,被格式化成 JDWP 数据包,发送给调试者并返回给 JDI 调用。而调试器开发人员就是通过 JDI 得到数据,发出指令。下图就展示了三者间的交互过程:

下面就简单介绍下这三个模块的主要功能:

Java 虚拟机工具接口(JVMTI)
JVMTI(Java Virtual Machine Tool Interface)即指 Java 虚拟机工具接口,它是一套由虚拟机直接提供的 native 接口,它处于整个 JPDA 体系的最底层,所有调试功能本质上都需要通过 JVMTI 来提供。通过这些接口,开发人员不仅调试在该虚拟机上运行的 Java 程序,还能查看它们运行的状态,设置回调函数,控制某些环境变量,从而优化程序性能。我们知道,JVMTI 的前身是 JVMDI 和 JVMPI,它们原来分别被用于提供调试 Java 程序以及 Java 程序调节性能的功能。在 J2SE 5.0 之后 JDK 取代了 JVMDI 和 JVMPI 这两套接口,JVMDI 在最新的 Java SE 6 中已经不提供支持,而 JVMPI 也计划在 Java SE 7 后被彻底取代。

Java 调试交互协议(JDWP)
JDWP(Java Debug Wire Protocol)是一个为 Java 调试而设计的一个通讯交互协议,它定义了调试器和被调试程序之间传递的信息的格式。在 JPDA 体系中,作为前端(front-end)的调试者(debugger)进程和后端(back-end)的被调试程序(debuggee)进程之间的交互数据的格式就是由 JDWP 来描述的,它详细完整地定义了请求命令、回应数据和错误代码,保证了前端和后端的 JVMTI 和 JDI 的通信通畅。比如在 Sun 公司提供的实现中,它提供了一个名为 jdwp.dll(jdwp.so)的动态链接库文件,这个动态库文件实现了一个 Agent,它会负责解析前端发出的请求或者命令,并将其转化为 JVMTI 调用,然后将 JVMTI 函数的返回值封装成 JDWP 数据发还给后端。
另外,这里需要注意的是 JDWP 本身并不包括传输层的实现,传输层需要独立实现,但是 JDWP 包括了和传输层交互的严格的定义,就是说,JDWP 协议虽然不规定我们是通过 EMS 还是快递运送货物的,但是它规定了我们传送的货物的摆放的方式。在 Sun 公司提供的 JDK 中,在传输层上,它提供了 socket 方式,以及在 Windows 上的 shared memory 方式。当然,传输层本身无非就是本机内进程间通信方式和远端通信方式,用户有兴趣也可以按 JDWP 的标准自己实现。

Java 调试接口(JDI)
JDI(Java Debug Interface)是三个模块中最高层的接口,在多数的 JDK 中,它是由 Java 语言实现的。 JDI 由针对前端定义的接口组成,通过它,调试工具开发人员就能通过前端虚拟机上的调试器来远程操控后端虚拟机上被调试程序的运行,JDI 不仅能帮助开发人员格式化 JDWP 数据,而且还能为 JDWP 数据传输提供队列、缓存等优化服务。从理论上说,开发人员只需使用 JDWP 和 JVMTI 即可支持跨平台的远程调试,但是直接编写 JDWP 程序费时费力,而且效率不高。因此基于 Java 的 JDI 层的引入,简化了操作,提高了开发人员开发调试程序的效率。
如下就总结了三个模块的不同点:

Java 调试接口的特点
Java 语言是第一个使用虚拟机概念的流行的编程语言,正是因为虚拟机的存在,使很多事情变得简单而轻松,掌握了虚拟机,就掌握了内存分配、线程管理、即时优化等等运行态。同样的,Java 调试的本质,就是和虚拟机打交道,通过操作虚拟机来达到观察调试我们自己代码的目的。这个特点决定了 Java 调试接口和以前其他编程语言的巨大区别。
以 C/C++ 的调试为例,目前比较流行的调试工具是 GDB 和微软的 Visual Studio 自带的 debugger,在这种 debugger 中,首先,我们必须编译一个“ debug ”模式的程序,这个会比实际的 release 模式程序大很多。其次,在调试过程中,debugger 将会深层接入程序的运行,掌握和控制运行态的一些信息,并将这些信息及时返回。这种介入对运行的效率和内存占用都有一定的需求。基于这些需求,这些 Debugger 本身事实上是提供了,或者说,创建和管理了一个运行态,因此他们的程序算法比较复杂,个头都比较大。对于远端的调试,GDB 也没有很好的默认实现,当然,C/C++ 在这方面也没有特别大的需求。
而 Java 则不同,由于 Java 的运行态已经被虚拟机所很好地管理,因此作为 Java 的 Debugger 无需再自己创造一个可控的运行态,而仅仅需要去操作虚拟机就可以了。 Java 的 JPDA 就是一套为调试和优化服务的虚拟机的操作工具,其中,JVMTI 是整合在虚拟机中的接口,JDWP 是一个通讯层,而 JDI 是前端为开发人员准备好的工具和运行库。
从构架上说,我们可以把 JPDA 看作成是一个 C/S 体系结构的应用,在这个构架下,我们可以方便地通过网络,在任意的地点调试另外一个虚拟机上的程序,这个就很好地解决了部署和测试的问题,尤其满足解决了很多网络时代中的开发应用的需求。前端和后端的分离,也方便用户开发适合于自己的调试工具。
从效率上看,由于 Java 程序本身就是编译成字节码,运行在虚拟机上的,因此调试前后的程序、内存占用都不会有大变化(仅仅是启动一个 JDWP 所需要的内存),任意程度都可以很好地调试,非常方便。而 JPDA 构架下的几个组成部分,JDWP 和 JDI 都比较小,主要的工作可以让虚拟机自己完成。
从灵活性上,Java 调试工具是建立在强大的虚拟机上的,因此,很多前沿的应用,比如动态编译运行,字节码的实时替换等等,都可以通过对虚拟机的改进而得到实现。随着虚拟机技术的逐步发展和深入,各种不同种类,不同应用领域中虚拟机的出现,各种强大的功能的加入,给我们的调试工具也带来很多新的应用。
总而言之,一个先天的,可控的运行态给 Java 的调试工作,给 Java 调试接口带来了极大的优势和便利。通过 JPDA 这个标准,我们可以从虚拟机中得到我们所需要的信息,完成我们所希望的操作,更好地开发我们的程序。

u010655288
u010655288   2015.05.28 17:40

我也是醉了!楼上几天回复够你看半天了!

Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!