用JPDA轻松调试Java代码

 在无法访问运行中的实例时,调试一个Java程序可能相当麻烦;当应用程序在远程环境下运行,并且不会在控制台或日志文件中输出任何结果时,调试工作变得更加困难。如果你需要对一个运行中的Java应用程序进行全方位调试,Sun的Java平台调试构架(JPDA)可为您提供帮助。

    JPDA是一组API集合,旨在帮助你调试Java代码。J2SE自1.2.2版开始推出JPDA工具集,并在1.3.x版中将它直接包含在J2SE软件包中。

    JPDA并非一个应用程序或调试工具,而是一组精心设计的接口与协议,了解这点很重要。Sun设计这一标准的目的是提供一个基础构架,以便第三方工具和调整器能够高效利用它。还有许多利用JPDA的优秀调试器和IDE,包括一些获得广泛认可的工具,如Borland JBuilder、Oracle JDeveloper、IntelliJ IDEA、Sun NetBeans、ibm Eclipse等等。不过,Sun在它的传统命令行式调试器jdb中提供了一个参考实例。Java 1.3重新编写了jdb以支持JPDA。在本文中,我将讨论JPDA技术及它的一些实际应用。

工作原理

    JPDA由三个接口构成,这些接口为桌面系统的开发环境而设计。Java虚拟机工具接口(JVMTI)定义虚拟机(VM)在调试时必须提供的服务。(在Java 5.0中,JVMTI替代已被删除的Java虚拟机调试接口)。Java调试线协议(JDWP)定义在调试过程和调试器前端之间传输的信息和请求的格式。它执行Java调试接口(JDI)。JDI定义用户代码级信息和请求。

    JPDA概念将调试过程分为两部分:被调试的程序(被调试者-debuggee)和JDI。JDI一般为一个调试应用程序的用户接口(或Java IDE的一部分)。被调试的应用程序在后端运行,而JDI在前端运行。在前端与后端之间有一个通信通道运行JDWP协议;因此,被调试程序与调试器可以位于同一个系统内,也可位于不同的系统中。

    从开发者的角度,一个调试应用程序可进入任何JPDA层面。因为JDI是最高层,也最容易使用,我们推荐使用这个接口。假设一家公司用JDI开发了一个调试器。公司能够把它用于参考实例中,它将自动与VM和Sun支持的平台协同工作,因此大多数IDE供应商采用这种方式。还可以这样,例如,参考实例在前端运行,被调试者运行另一家公司执行JDWP(它可能运行或忽略JVMTI)的VM。

    一些调试器可能建立在较低层面之上,如JDWP(例如,如果Java没有编写前端)或JVMTI(针对需要低级功能的专用调试器)。

    调试器的后端负责由调试器前端向被调试者VM传输请求,如“告诉我变量X的值”;它还负责向前端传输对这些请求(包括像到达断点之类的预计事件)的响应。后端与前端利用JDWP通过一个通信通道进行通信。后端与被调试者VM利用JVMTI进行通信。

    通信通道连接调试器的前端与后端。可以认为它由两个装置组成:一个连接器和一个传送器。连接器是一个JDI对象,它在前端与后端建立连接;可能有三种类型的连接器:

  • 收听型:前端从后端收听一个进入的连接。
  • 依附型:前端依附到一个已运行的后端上。
  • 发布型:前端发布运行被调试者代码和后端的Java过程。

    传送器是在前端和后端传输信息的基本装置。在JPDA规范中没有指定必须使用的传送器装置。可能的装置包括:套接字、串行线路和共享内存。但是,JDWP指定了流经通道的连续化位流的格式与语义。许多IDE和调试器都支持两种类型的传送器(Sun的参考实例就是如此):共享内存(如果被调试者和调试器位于同一系统)和套接字(被调试者和调试器可位于任何地方,包括同一系统)。

    从J2SE 5.0开始,JPDA包括了服务提供器接口,允许对连接器与传送器实例进行开发与配置。这些服务提供器服务接口允许调试器和其它工具供应商开发新的连接器实例,并提供除Sun的套接字和共享内存以外的其它传送器装置。

    被调试者与调试器之间的通信以连接为导向。因此,一方必须作为服务器,收听一个连接;另一方作为一个客户端连接到服务器。JPDA允许以调试应用程序和目标VM为服务器。

JPDA实际应用

    如果你需要使用套接字传送器,在对应的JVM中以dt_socket为名确定自变量的类型。如果被调试者和调试器位于同一机器之中,且运行的是Windows系统,你可以使用名为dt_schmem的共享内存连接器。如果你希望用一个与JPDA兼容的调试器调试应用程序,你应在调试模式下运行调试器,并提交其它参数,如传送器类型、主机名称、端口号及其它信息。所有JPDA和调试参数必须在启动应用程序时作为自变量提交。

    要进行调试,你必须将调试JDWP代理加载到应用程序的JVM中。从Java 5.0开始,你可以用-agentlib:jdwp选项来完成加载。5.0以前版本则使用-Xdebug和-Xrunjdwp选项(5.0也支持-Xdebug和-Xrunjdwp选项,不过新的-agentlib:jdwp选项更加好用。因为5.0中的JDWP代理使用JVMTI接口连接VM,而非旧的JVMDI接口)。你应该向-agentlib:jdwp(Java 5.0中)或-Xrunjdwp(Java 5.0以前版本) 参数提供子选项;两组可能的子选项相同。

以下列方式指定子选项:

-agentlib:jdwp=<name1>[=<value1>],<name2>[=<value2>]...

-Xrunjdwp:<name1>[=<value1>],<name2>[=<value2>]...

你可以使用这些选项:

  • help:打印如何应用它的简单信息,并退出VM。
  • server:(是”y”或否”n”):如“server=y”,收到一个要依附的调试应用程序;如“server=n”,依附到指定地址的调试应用程序。
  • address:连接传送地址。如果server=n,尝试依附到这个地址的调试应用程序;如server=y,收到这个地址的连接。
  • timeout:如果server=y,它以毫秒为单位指定等待调试器依附的时间;如server=n,它以毫秒为单位指定依附到调试器所用的时间。
  • suspend:如“是”,JVM延缓执行,直到调试器与被调试JVM建立连接。

以下是命令行实例:

-agentlib:jdwp=transport=dt_socket,server=y,address=8000

在端口8000收听一个套接字连接。在主类加载前延缓这个VM(默认suspend=y)。一旦连接上调试应用程序,它发送一个JDWP命令恢复VM。

-agentlib:jdwp=transport=dt_shmem,server=y,suspend=n

选择一个有效的共享内存传输地址并将它打印出来。在那个地址收听一个共享内存连接。在调试应用程序依附之前,允许VM开始执行。

-agentlib:jdwp=transport=dt_socket,address=myhost:8000

通过myhost主机端口8000的套接字依附到一个运行的调试应用程序。在主类加载前延缓这个VM。

 
发布了582 篇原创文章 · 获赞 35 · 访问量 329万+
展开阅读全文

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

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览