如何使用热点动态附加机制访问 JVM 内部数据结构?
How to access JVM internal data structures using the Hotspot Dynamic Attach Mechanism?
根据 OpenJDK's website,可以将线程附加到热点(动态附加 API),它可以收集有关它的信息。我在互联网上找不到任何关于如何获取有关 Hotspot 内部数据结构的信息,例如操作数堆栈或字节码解释器的状态(以了解当前正在执行的字节码)或检索当前的任何 material堆栈框架等
此外,如果使用动态附加 API 无法做到这一点,如何使用可服务性代理来完成?我在 Internet 上找到的唯一示例是 this gist from Github,它显示了如何附加到 运行 JVM 并获取某些字段的值。但是如何在JVM中访问上述内部数据结构呢?
文章 Creating Your Own Debugging Tools 简要介绍了动态附加和可服务性代理。
动态附加允许连接到 运行 JVM 并执行预定义命令 之一,如
- 打印堆栈跟踪
- 转储堆
- 查询或设置 VM 标志
- 加载代理库
- 等等
基本上,标准的jstack
、jmap
和jcmd
工具几乎涵盖了Dynamic Attach提供的所有功能。此 API 是 而不是 用于访问内部 JVM 结构。我怀疑它能否帮助您完成任务,除了加载自定义 JVM TI 库。
Serviceability Agent 更接近于 JVM 内部结构。事实上,它可以读取 JVM 内存并恢复代码缓存、堆栈框架、TLAB、常量池等结构
SA javadoc 在 JDK 个来源中可用 here. There are some examples 个基于 SA 的工具。
但是SA也不符合你的要求
- 这是一个只读界面。
- 它在流程之外工作。基于 SA 的工具完全挂起 JVM 进程并使用 ptrace.
读取其内存
- 速度比较慢。它的主要目的是调试无响应(或死机)的 JVM 进程。
关于操作数栈,字节码指针等,这些概念只存在于解释器中。一旦方法经过 JIT 编译,它就不再具有您询问的结构。
- 局部变量和操作数可以在CPU寄存器中分配或转换为常量。
- 机器码并不总是一对一映射到字节码。
- 内联方法甚至可能没有自己的栈帧,等等。
一个一个执行字节码意味着放弃JIT编译。 JVM TI SingleStep 确实只在解释器中工作。 Java 应用程序在纯解释模式下的运行速度可能会慢 10-100 倍。
如果您想保持调试器的合理性能,一个接一个地处理每个字节码指令不是一种选择。如前所述,检测是正确的方法。请注意,没有必要拦截每个字节码 - 检测 basic blocks 就足够了。
根据 OpenJDK's website,可以将线程附加到热点(动态附加 API),它可以收集有关它的信息。我在互联网上找不到任何关于如何获取有关 Hotspot 内部数据结构的信息,例如操作数堆栈或字节码解释器的状态(以了解当前正在执行的字节码)或检索当前的任何 material堆栈框架等
此外,如果使用动态附加 API 无法做到这一点,如何使用可服务性代理来完成?我在 Internet 上找到的唯一示例是 this gist from Github,它显示了如何附加到 运行 JVM 并获取某些字段的值。但是如何在JVM中访问上述内部数据结构呢?
文章 Creating Your Own Debugging Tools 简要介绍了动态附加和可服务性代理。
动态附加允许连接到 运行 JVM 并执行预定义命令 之一,如
- 打印堆栈跟踪
- 转储堆
- 查询或设置 VM 标志
- 加载代理库
- 等等
基本上,标准的jstack
、jmap
和jcmd
工具几乎涵盖了Dynamic Attach提供的所有功能。此 API 是 而不是 用于访问内部 JVM 结构。我怀疑它能否帮助您完成任务,除了加载自定义 JVM TI 库。
Serviceability Agent 更接近于 JVM 内部结构。事实上,它可以读取 JVM 内存并恢复代码缓存、堆栈框架、TLAB、常量池等结构
SA javadoc 在 JDK 个来源中可用 here. There are some examples 个基于 SA 的工具。
但是SA也不符合你的要求
- 这是一个只读界面。
- 它在流程之外工作。基于 SA 的工具完全挂起 JVM 进程并使用 ptrace. 读取其内存
- 速度比较慢。它的主要目的是调试无响应(或死机)的 JVM 进程。
关于操作数栈,字节码指针等,这些概念只存在于解释器中。一旦方法经过 JIT 编译,它就不再具有您询问的结构。
- 局部变量和操作数可以在CPU寄存器中分配或转换为常量。
- 机器码并不总是一对一映射到字节码。
- 内联方法甚至可能没有自己的栈帧,等等。
一个一个执行字节码意味着放弃JIT编译。 JVM TI SingleStep 确实只在解释器中工作。 Java 应用程序在纯解释模式下的运行速度可能会慢 10-100 倍。
如果您想保持调试器的合理性能,一个接一个地处理每个字节码指令不是一种选择。如前所述,检测是正确的方法。请注意,没有必要拦截每个字节码 - 检测 basic blocks 就足够了。