如何调试使用 JVMTI 代理设置断点的 java 应用程序(无法获得必要的 JVMTI 功能)
How to debug a java app that uses a JVMTI agent to set breakpoint (Unable to get necessary JVMTI capabilities)
我想调试 java 使用我编写的 jvmti 代理的应用程序。这似乎只有在 jvmti 代理不尝试启用 "can_generate_breakpoint_events" 功能时才有效。
尝试启用断点功能并在调试模式下启动应用会导致以下错误:
ERROR: JVMTI: 98(Unknown): Unable to get necessary JVMTI capabilities. [..\src\agent.cpp:437]
有什么方法可以调试使用设置断点的 jvmti 代理的应用程序吗?
我检查了 Java JVMTI doesn't work alongside -Xdebug -Xrunjdwp 但接受的答案似乎并不正确,因为它似乎也确实取决于启用的功能。
我知道探查器(如 YourKit 等)也在使用 jvmti 代理,并且仍然允许您 运行 您的应用程序处于调试模式(好吧,也许他们只是没有使用导致这些冲突)。
TL;DR
要调试 JVM 代理,请使用本机代码调试器,例如gdb.
稍微详细一些
Java 应用程序中存在两种代码 - Java 代码(应用程序本身和基于 java.lang.instrument 的代理)和本机代码([的本机方法) =27=] 类、JVMTI 代理和 VM 本身)。要调试前者,您需要使用 Java 调试器(使用 JDWP)。要调试后者,您需要像对待 C/C++ 程序一样使用常规本机代码调试器。如果您想同时调试 Java 和本机代码,那么您需要同时使用这两个调试器。
关于JVMTI代理、JDWP以及需要什么
一个 JVM 可以与多个代理一起启动 运行,每个代理都有自己的 JVMTI 环境(功能、事件侦听器等)。但是,如果多个代理(或单个代理的多个实例)使用相同的资源,例如相同的全局变量,那么它们可以相互影响(JDK 的 JDWP 代理就是这种情况 - 这就是为什么你最多可以有一个 -agentlib:jdwp
)。
JDWP 是 Java 调试器的协议。 JDWP 代理是 JDK 附带的 JVMTI 代理,它支持 JVM 中的 JDWP 协议。它是一个普通的 JVMTI 代理,可以与其他代理一起启动。
根据我目前的理解,答案实际上如下。来自 JVMTI 文档:
The potentially available capabilities of each JVM TI implementation are different. Depending on the implementation, a capability:
- ...
- may be possessed by only one environment at a time
- ...
设置断点和观察点似乎是一种只能由一个环境拥有的能力。
所以问题是我的代理试图声明 can_generate_breakpoint 功能,但调试器代理也需要它们。因此,有两个代理请求这些导致上述错误的功能。
因此,对我来说,这意味着您无法调试使用需要能够设置断点的 JVM TI 代理启动的 Java 应用程序。
我能想到的唯一理论上的解决方案是我的 JVM TI 代理另外实现了对 JDWP 的支持并允许调试器连接到它(我想这本身就是一个相当大的项目)
我想调试 java 使用我编写的 jvmti 代理的应用程序。这似乎只有在 jvmti 代理不尝试启用 "can_generate_breakpoint_events" 功能时才有效。
尝试启用断点功能并在调试模式下启动应用会导致以下错误:
ERROR: JVMTI: 98(Unknown): Unable to get necessary JVMTI capabilities. [..\src\agent.cpp:437]
有什么方法可以调试使用设置断点的 jvmti 代理的应用程序吗?
我检查了 Java JVMTI doesn't work alongside -Xdebug -Xrunjdwp 但接受的答案似乎并不正确,因为它似乎也确实取决于启用的功能。
我知道探查器(如 YourKit 等)也在使用 jvmti 代理,并且仍然允许您 运行 您的应用程序处于调试模式(好吧,也许他们只是没有使用导致这些冲突)。
TL;DR
要调试 JVM 代理,请使用本机代码调试器,例如gdb.
稍微详细一些
Java 应用程序中存在两种代码 - Java 代码(应用程序本身和基于 java.lang.instrument 的代理)和本机代码([的本机方法) =27=] 类、JVMTI 代理和 VM 本身)。要调试前者,您需要使用 Java 调试器(使用 JDWP)。要调试后者,您需要像对待 C/C++ 程序一样使用常规本机代码调试器。如果您想同时调试 Java 和本机代码,那么您需要同时使用这两个调试器。
关于JVMTI代理、JDWP以及需要什么
一个 JVM 可以与多个代理一起启动 运行,每个代理都有自己的 JVMTI 环境(功能、事件侦听器等)。但是,如果多个代理(或单个代理的多个实例)使用相同的资源,例如相同的全局变量,那么它们可以相互影响(JDK 的 JDWP 代理就是这种情况 - 这就是为什么你最多可以有一个 -agentlib:jdwp
)。
JDWP 是 Java 调试器的协议。 JDWP 代理是 JDK 附带的 JVMTI 代理,它支持 JVM 中的 JDWP 协议。它是一个普通的 JVMTI 代理,可以与其他代理一起启动。
根据我目前的理解,答案实际上如下。来自 JVMTI 文档:
The potentially available capabilities of each JVM TI implementation are different. Depending on the implementation, a capability:
- ...
- may be possessed by only one environment at a time
- ...
设置断点和观察点似乎是一种只能由一个环境拥有的能力。
所以问题是我的代理试图声明 can_generate_breakpoint 功能,但调试器代理也需要它们。因此,有两个代理请求这些导致上述错误的功能。
因此,对我来说,这意味着您无法调试使用需要能够设置断点的 JVM TI 代理启动的 Java 应用程序。
我能想到的唯一理论上的解决方案是我的 JVM TI 代理另外实现了对 JDWP 的支持并允许调试器连接到它(我想这本身就是一个相当大的项目)