java 断点取消_在线/不重启/不暂停的对Java应用进行Debug,通过程序打断点并输出断点信息...

310605afca0a635cbb7ce41e3a938711.png

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

9989b606687cfe1e5e85f1d4582ce06d.png

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

a088c418115d54eceff09d6131a31bb4.png

什么时JDI

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

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

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

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

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

2. 引用类库

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

3. 连接远程JVM

aafa6c0038454bd93e9f3dd9333688c4.png

4. 标记断点

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

8638bded8edeeba3df24d3f3f9c7fe79.png

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

adf74e75601ccb41c492145949b13546.png

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

5. 跟踪断点

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

165953d0e687b82a660284905422112b.png

6. 获取断点信息

如下代码:

2bffe68b8a52d339d1d22e49226790b9.png

9587865e6b2a47ae33dbc8e7a53536cd.png

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

7. 解析获取的变量

0566a1733d18a2fd59ab4800261df5ab.png

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

8781ba7c707afeccb9442dca544d04d2.png

8. 测试:启动目标程序

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

fee032a4bd0b70bc6404dcfdeca8bd9c.png

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

9. 测试:执行debug程序

代码如下:

bf75993d80bba597dd79862465cd5171.png

输出结果如下:

4210f570b1ed693168f8b719c2ffa473.png

—————END—————

看完本文有意思?请分享给更多人

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 Apollo 框架中编写代码后,可以通过 `./apollo.sh build_dbg` 命令进行编译,然后可以使用调试工具来进行调试。以下是一些常用的调试方法: 1. 使用 GDB:GDB 是一个常用的调试工具,在调试期间可以使用 GDB 来分析和调试 Apollo 代码。首先,确保你的编译是在 Debug 模式进行的(例如 `./apollo.sh build_dbg`)。然后,在终端中运行以下命令启动 GDB 调试: ``` gdb --args ./path/to/your/compiled/executable ``` 这将启动 GDB 并将你的可执行文件作为参数传递给它。接下来,你可以使用 GDB 的各种命令(例如设置断点、单步执行、查看变量值等)来进行调试。 2. 使用 Visual Studio Code:如果你使用 Visual Studio Code 编辑器,可以使用其内置的调试功能来调试 Apollo 代码。首先,确保你的编译是在 Debug 模式进行的。然后,在 Visual Studio Code 中打开 Apollo 代码的目录,并在左侧面板中选择“调试”选项卡。点击“添加配置”按钮,并选择适合你的调试环境(例如 GDB 或 LLDB)。根据你的配置,编辑 `launch.json` 文件以指定可执行文件的路径和其他调试选项。最后,点击调试按钮(绿色的三角形图标)以启动调试。 这些是一些常见的调试方法,你可以根据自己的偏好和开发环境选择适合自己的方式进行调试。此外,还可以参考 Apollo 官方文档中关于调试的详细说明,以获取更多关于调试的信息和技巧。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值