在线不重启不暂停的对Java应用进行De

平时我们进行程序开发时经常需要通过Debug的方式查看代码运行到某一行时的上下文变量信息,以便进行代码调式分析。但是在生产环境下,正在线上运行的程序如果发现有问题需要进行调式,如果手动SocketRemote连接并设置断点并跟踪断点信息,会造成程序阻塞,影响线上正在运行的业务。本文将通过JavaJDI技术,介绍如何在程序正常运行的情况下,通过Java代码在不阻塞程序正常运行的情况下获取某一个代码行执行时的上下文变量信息,可以动态打断点并输出断点信息。

在介绍JDI之前,首先看一下传统的SocketRemoteDebug

使用IDE进行Debug,可以使用IDE中内嵌的Tomcat进行调式,或使用SocketRemote方式调式,例如在IntellijIDEA中可以参照如下方式为程序设置远程调式端口:

启动上面的程序。之后设置进行debug的代码,如下设置要debug远程的地址和端口:

配置好后,按照如下方法启动debug即可:

什么时JDI

JPDA(JavaPlatformDebuggerArchitecture)是Java平台调试体系结构的缩写,通过JPDA提供的API,开发人员可以方便灵活的搭建Java调试应用程序。JPDA主要由三个部分组成:Java虚拟机工具接口(JVMTI),Java调试线协议(JDWP),以及Java调试接口(JDI)。JDI(JavaDebugInterface)是JPDA三层模块中最高层的接口,定义了调试器(Debugger)所需要的一些调试接口。基于这些接口,调试器可以及时地了解目标虚拟机的状态,例如查看目标虚拟机上有哪些类和实例等。另外,调试者还可以控制目标虚拟机的执行,例如挂起和恢复目标虚拟机上的线程,设置断点等。

使用JDI编写代码进行远程调式

1.被调式程序设置调式端口

被调式程序启动时添加允许远程调式的启动参数:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=

2.引用类库

每个JavaJDK都有自己的JDI接口实现,标准的OracleJDK的JDI接口放在jdk/lib/tools.jar中,因此写代码时首先需要引入这个jar。

3.连接远程JVM

4.标记断点

如下代码,需指定要标记断点的类和行数。注意一个类或者行可能会有多个线程来调用,但是示例代码中为了简单考虑只获取了第一个调用线程的结果,即get(0)。此外,给行打断点时,所设置的行数必须是有效代码的行。例如如果所设置的行是回车没有Java代码,则会抛出异常。

如上注册了一个Breakpoint类型的事件请求,而系统除了提供断点事件外还提供了很多其他的事件类型:

不同的事件需要被分类地添加到不同的事件集合(EventSet)中,事件集是事件发送的最小单位。事件集一旦创建出来,便不可再被修改。生成的事件将被依次地加入到目标虚拟机的事件队列(EventQueue)中。然后,EventQueue将这些事件集以“先进先出”策略依次地发送到调试器端。EventQueue负责管理来自目标虚拟机的事件,一个被调试的目标虚拟机上有且仅有一个EventQueue实例。特别地,随着一次事件集的发送,目标虚拟机上可能会有一部分的线程因此而被挂起。如果一直不恢复这些线程,有可能会导致目标虚拟机挂机。因此,在处理好一个事件集中的事件后,建议调用事件集的resume()方法,恢复所有可能被挂起的线程。

5.跟踪断点

如下代码,获取事件时需要根据事件类型进行相应的处理:

6.获取断点信息

如下代码:

调用BreakpointEvent的thread()可以获取产生事件的线程镜像(ThreadReference),调用ThreadReference的frame(int)可获得当前代码行所在的堆栈(StackFrame),调用StackFrame的visibleVariables()可获取当前堆栈中的所有本地变(LocaleVariable)。通过调用BreakpointEvent的location()可获得断点所在的代码行号(Location),调用Location的method()可获得当前代码行所归属的方法。通过以上调用,调试器便可获得了目标虚拟机上线程、对象、变量等镜像信息。

7.解析获取的变量

Value和Type接口分别代表着目标虚拟机中对象、实例变量和方法变量的值和类型。通过Value接口的type(),可以获取该值对应的类型。JDI中定义了两种基本的数据类型:原始类型(PrimitiveType)和引用类(ReferenceType)。与其对应的数值类型分别是原始值(PrimtiveValue)和对象引用(ObjectReference),Value和Type的具体对应关系如下:

8.测试:启动目标程序

测试目标类如下,计划在System.out.println行打断点,为了演示方便通过Thread.sleep添加暂停事件,以便启动调式程序:

启动时添加远程debug参数并运行。

9.测试:执行debug程序

代码如下:

输出结果如下:

赞赏

人赞赏









































广东白癜风医院
昆明治白癜风最好的医院


转载请注明地址:http://www.haikouwanbao.com/hkrbjj/2975.html


  • 上一篇文章:
  • 下一篇文章:
  • 网站简介 广告合作 发布优势 服务条款 隐私保护 网站地图 版权声明