【问题标题】:How to access JVM internal data structures using the Hotspot Dynamic Attach Mechanism?如何使用 Hotspot Dynamic Attach Mechanism 访问 JVM 内部数据结构?
【发布时间】:2023-04-04 15:56:01
【问题描述】:

根据OpenJDK's website,可以将线程附加到Hotspot(动态附加API),它可以收集有关它的信息。我在 Internet 上找不到任何有关如何获取有关 Hotspot 内部数据结构的信息的材料,例如操作数堆栈或字节码解释器的状态(以了解当前正在执行的字节码)或检索当前堆栈帧等。

另外,如果动态附加 API 无法做到这一点,那么如何使用 Serviceability Agent 来实现呢?我在 Internet 上找到的唯一示例是 this gist from Github,它显示了如何附加到正在运行的 JVM 并获取某些字段的值。但是如何访问上述JVM中的内部数据结构呢?

【问题讨论】:

  • jvmti 具有或多或少您提到的所有功能(正在执行的字节码、当前堆栈帧等)
  • 您的目标到底是什么?你想做什么?
  • @PiRocks 我正在尝试构建一个反向调试器(您可以退后一步)...我尝试使用 JVMTI,但这些函数会导致过多的开销。基本上我想要实现的是在每个执行的行获取最重要的JVM结构的值(并存储它)。
  • 字节码检测可能是你最好的选择。

标签: java debugging jvm jvm-hotspot jvmti


【解决方案1】:

文章Creating Your Own Debugging Tools 简要介绍了动态附加和可服务性代理。

Dynamic Attach 允许连接到正在运行的 JVM 并执行 预定义命令之一,例如

  • 打印堆栈跟踪
  • 转储堆
  • 查询或设置 VM 标志
  • 加载代理库

基本上,标准的jstackjmapjcmd 工具几乎涵盖了 Dynamic Attach 提供的所有功能。此 API用于访问内部 JVM 结构。我怀疑它对您的任务有帮助,除了加载自定义 JVM TI 库。


Serviceability Agent 更接近 JVM 内部结构。事实上,它可以读取 JVM 内存并恢复代码缓存、堆栈帧、TLAB、常量池等结构。

SA javadoc 可用here。 JDK 源码中有some examples 个基于 SA 的工具。

但是,SA 也不符合您的要求。

  1. 它是一个只读界面。
  2. 它在进程之外起作用。基于 SA 的工具完全挂起 JVM 进程并使用 ptrace 读取其内存。
  3. 相当慢。它的主要目的是调试无响应(或死)的 JVM 进程。

关于操作数栈、字节码指针等。这些概念只存在于解释器中。一旦一个方法被 JIT 编译,它就不再有你所询问的结构。

  • 局部变量和操作数可以在 CPU 寄存器中分配或转换为常量。
  • 机器码并不总是一对一地映射到字节码。
  • 内联方法甚至可能没有自己的堆栈框架,等等。

逐个执行字节码意味着放弃JIT编译。 JVM TI SingleStep 确实只在解释器中有效。 Java 应用程序在纯解释模式下的运行速度可能会慢 10-100 倍。

如果您想保持调试器的性能合理,则不能一个接一个地处理每个字节码指令。如前所述,仪器仪表是正确的方法。请注意,不必拦截每个字节码 - 检测 basic blocks 就足够了。

【讨论】:

  • 感谢您的详细解释。我有最后一个想法:跟踪 JVM 中的堆修改(堆版本控制)并在给定的时间重建堆的状态(然后可以由 Serviceability Agent 分析以提取对象信息)。但是我认为如果不修改 JVM 本身这是不可能的(我认为这可以通过拦截 JVM 完成的每个内存访问来实现,但是在互联网上阅读之后,似乎这真的很慢)。顺便说一句,赏金我会奖励给你的,只是我还需要等一天。
猜你喜欢
  • 2012-01-30
  • 1970-01-01
  • 2013-08-01
  • 2016-09-10
  • 2021-05-13
  • 1970-01-01
  • 2010-12-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多