如何获取 Java 本机代理出错时的 *native* 堆栈跟踪?
How to get *native* stack-trace on error for Java native agent?
我的老板想让我看看我是否可以在我们的 Java 客户端中为我们的测试人员写一个 "one button memory leak checker"(因为这样我自己就可以花更少的时间 运行分析器下的完整手动测试套件;我们没有自动测试套件)。
我发现了一些非常接近我需要的东西:Heap Walker 我不得不稍微修改它以便在 Windows 中的 VS 中编译(我认为它是为 GCC 在 Mac).但是当我 运行 它时,JVM 崩溃了。
我想获得本机堆栈跟踪以至少查看它崩溃的位置,以及是否可以找出发生了什么,但我不知道如何。我已经构建了一个 "debug" DLL,但我仍然没有得到堆栈跟踪。既不在控制台上,也不在 JVM 生成的 "hs_err_pidXXXX.log" 文件中。
我已经有 15 年没做过 C/C++ 了;我仍然可以了解 "guess" 代码的作用,但我忘记了调试是如何进行的(超出 "printf everywhere" ...),而且我从来没有在 JVM 中调试本机代码。到目前为止,Google 没有帮助;我可能使用了错误的搜索词。
JVM 通常在故障转储中报告本机堆栈跟踪。如果 hs_err_pid.log
中没有堆栈跟踪,则表示 JVM 无法从 PC 寄存器获取最后一帧,通常是因为它指向不可读的地址。
例如,如果本机代码取消引用空函数指针,就会发生这种情况:
void (*func)() = 0;
func();
在这种情况下,PC 将为零,并且 JVM 不会打印跟踪。但是您仍然可以从堆栈中找到调用方 PC,因为 return 地址通常在调用之前被压入堆栈。以下是如何在 hs_err_pid.log
中找到它:
Top of Stack: (sp=0x0000000002e2f438)
0x0000000002e2f438: 00007ffcf03f1030 00007ffcf041d000
^^^^^^^^^^^^^^^^
the return address (the address after the last valid instruction)
然后就可以在Dynamic libraries
段找到这个地址,计算出从dll开头的偏移量。
Dynamic libraries:
...
0x00007ffcf03f0000 - 0x00007ffcf0426000 C:\Java\Test\crash.dll
^^^^^^^^^^^^^^^^^^
offset = 0x00007ffcf03f1030 - 0x00007ffcf03f0000 = 0x1030
使用反汇编程序(例如 Visual Studio 的 dumpbin)将偏移量解码为代码中的特定函数/指令。
您还可以在 JVM 崩溃时将 Visual Studio 调试器附加到它。为此,您应该 运行 Java 和 -XX:+ShowMessageBoxOnError
。以下window邀请您连接调试器:
我的老板想让我看看我是否可以在我们的 Java 客户端中为我们的测试人员写一个 "one button memory leak checker"(因为这样我自己就可以花更少的时间 运行分析器下的完整手动测试套件;我们没有自动测试套件)。
我发现了一些非常接近我需要的东西:Heap Walker 我不得不稍微修改它以便在 Windows 中的 VS 中编译(我认为它是为 GCC 在 Mac).但是当我 运行 它时,JVM 崩溃了。
我想获得本机堆栈跟踪以至少查看它崩溃的位置,以及是否可以找出发生了什么,但我不知道如何。我已经构建了一个 "debug" DLL,但我仍然没有得到堆栈跟踪。既不在控制台上,也不在 JVM 生成的 "hs_err_pidXXXX.log" 文件中。
我已经有 15 年没做过 C/C++ 了;我仍然可以了解 "guess" 代码的作用,但我忘记了调试是如何进行的(超出 "printf everywhere" ...),而且我从来没有在 JVM 中调试本机代码。到目前为止,Google 没有帮助;我可能使用了错误的搜索词。
JVM 通常在故障转储中报告本机堆栈跟踪。如果 hs_err_pid.log
中没有堆栈跟踪,则表示 JVM 无法从 PC 寄存器获取最后一帧,通常是因为它指向不可读的地址。
例如,如果本机代码取消引用空函数指针,就会发生这种情况:
void (*func)() = 0;
func();
在这种情况下,PC 将为零,并且 JVM 不会打印跟踪。但是您仍然可以从堆栈中找到调用方 PC,因为 return 地址通常在调用之前被压入堆栈。以下是如何在 hs_err_pid.log
中找到它:
Top of Stack: (sp=0x0000000002e2f438)
0x0000000002e2f438: 00007ffcf03f1030 00007ffcf041d000
^^^^^^^^^^^^^^^^
the return address (the address after the last valid instruction)
然后就可以在Dynamic libraries
段找到这个地址,计算出从dll开头的偏移量。
Dynamic libraries:
...
0x00007ffcf03f0000 - 0x00007ffcf0426000 C:\Java\Test\crash.dll
^^^^^^^^^^^^^^^^^^
offset = 0x00007ffcf03f1030 - 0x00007ffcf03f0000 = 0x1030
使用反汇编程序(例如 Visual Studio 的 dumpbin)将偏移量解码为代码中的特定函数/指令。
您还可以在 JVM 崩溃时将 Visual Studio 调试器附加到它。为此,您应该 运行 Java 和 -XX:+ShowMessageBoxOnError
。以下window邀请您连接调试器: