c++ - 如何在 Java native 代理出错时获取 *native* 堆栈跟踪?

标签 c++ jvm javaagents

我的老板想让我看看我是否可以在我们的 Java 客户端中为我们的测试人员编写一个“一键内存泄漏检查器”(因为这样我就可以花更少的时间自己在分析器下运行我们的完整手动测试套件;我们没有自动化测试套件)。

我找到了非常接近我需要的东西:Heap Walker我不得不稍微修改它以在 Windows 中的 VS 中编译(我认为它是为 Mac 下的 GCC 制作的)。但是当我运行它时,JVM 崩溃了。

我想要一个 native 堆栈跟踪以至少查看它崩溃的位置,如果我能找出发生了什么,但我不知道如何。我已经构建了一个“调试”DLL,但我仍然没有得到堆栈跟踪。既不在控制台上,也不在 JVM 生成的“hs_err_pidXXXX.log”文件中。

我已经有大约 15 年没有接触过任何 C/C++ 了;我仍然可以“猜测”代码的作用,但我忘记了调试是如何进行的(除了“无处不在的 printf”......),而且我从来没有必要在 JVM 中调试 native 代码。到目前为止,谷歌没有任何帮助;我可能使用了错误的术语进行搜索。

最佳答案

JVM 通常在崩溃转储中报告 native 堆栈跟踪。如果 hs_err_pid.log 中没有堆栈跟踪,则表示 JVM 无法从 PC 寄存器获取最后一帧,通常是因为它指向不可读的地址。

例如,如果 native 代码取消引用空函数指针,就会发生这种情况:

void (*func)() = 0;
func();

在这种情况下,PC 将为零,并且 JVM 不会打印跟踪。但是您仍然可以从堆栈中找到调用方 PC,因为返回地址通常在调用之前被压入堆栈。以下是如何在 hs_err_pid.log 中找到它:

Top of Stack: (sp=0x0000000002e2f438)
0x0000000002e2f438:   00007ffcf03f1030 00007ffcf041d000
                      ^^^^^^^^^^^^^^^^
                      the return address (the address after the last valid instruction)

然后你可以在动态库部分找到这个地址,并计算从dll开头的偏移量。

Dynamic libraries:
...
0x00007ffcf03f0000 - 0x00007ffcf0426000    C:\Java\Test\crash.dll
^^^^^^^^^^^^^^^^^^
offset = 0x00007ffcf03f1030 - 0x00007ffcf03f0000 = 0x1030

使用反汇编程序(例如 Visual Studio 的 dumpbin )将偏移量解码为代码中的特定函数/指令。


您还可以在 JVM 崩溃时将其附加到 Visual Studio 调试器。为此,您应该使用 -XX:+ShowMessageBoxOnError 运行 Java。以下窗口将邀请您连接调试器:

ShowMessageBoxOnError

关于c++ - 如何在 Java native 代理出错时获取 *native* 堆栈跟踪?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38766360/

相关文章:

java - 使用 JMX 获取远程 JVM 属性

java - Byte Buddy 将 Try block 添加到现有方法中

C++跳转到其他方法执行

java - 在使用 Gradle 构建的 Java 项目中管理 javaagent 依赖项

c++ - InitCommonControlsEx() 在 Windows 8.1 中因 ICC_LINK_CLASS 而失败

c++ - nuwen.net MinGW Distro 中没有 `fileno()` 功能?

c++ - C++ 中奇怪的后增量行为

c++ - 任何人都有确定麻将游戏是否获胜的算法?

java - 解释字节码与编译字节码?

java - Tomcat 和 Matlab 编译器运行时内存不足错误