在.Net中,我们可以使用!DumpStack从转储中打印调用堆栈中的托管和非托管代码方法,我是否可以知道Java中是否还有一个可以同时打印托管和未管理的调用堆栈?
答案 0 :(得分:1)
首先,我想评论这个问题对我来说似乎没问题,我发现关闭你之前的问题和一些令人震惊的评论,再次证明了SO的大部分问题。
如果问这些关于.NET的问题是否正常,那么询问他们关于Java,即使答案结果是&# 34;你不能"。
(我将加入并挑选片刻:" Managed"是在CLR下运行的代码的Microsoft术语。你想问一些类似于"我怎么能在WinDbg中获取一个可用的堆栈跟踪,其中包含JVM本机代码和在其中运行的JITted Java代码?")
现在问你的问题:
不幸的是,我不知道WinDbg的工具或插件可以做到这一点,但我认为有一种方法可以让你自己制作一个。 (我以为我可以接受它,但我找不到时间,所以我想我至少会给你提供信息。既然你问了两次这个问题,我想这可能很重要所以你很难采取必要的步骤。)
解决您的问题可以分为两部分:
我会按顺序讨论它们并完成一些警告。
Brendan Gregg basically the same problem with profiling Java code。他需要JITted代码的函数名称。解决方案,用他自己的话说:
解决上述两个问题的一种方法是:
- JVMTI代理perf-map-agent,可以为perf提供Java符号表(/tmp/perf-PID.map)。
- 修补JDK热点,重新引入帧指针寄存器,允许完全堆栈行走。
醇>
JVMTI代表Java虚拟机工具接口。 JVMTI代理基本上是JVM的插件,它为他感兴趣的JVM事件实现回调。它可以动态加载或链接到JVM二进制文件中(如果您正在进行JVM的自定义构建)。
在perf-map-agent的情况下,插件要求了解所有JITted方法和一些其他动态生成的代码。它得到了他们的名字,地址和大小。然后它将此信息吐出到稍后由Linux perf。
使用的文件中你应该分叉它,更改任何特定于Linux的东西(我没有注意到任何东西,但可能有隐藏的东西)并在Windows中将其构建为DLL Windows版的HotSpot。
您还应该更改生成输出文件的函数(在src/c/perf-map-file.c
中),以您可以使WinDbg使用的格式输出信息,这将我们带到第二部分。
有几种方法可以让WinDbg消耗由JVMTI代理生成的符号,你可以考虑更多。我会想到一些想到的东西:
选项3对我来说似乎最简单(并且从我的经验中效果最好)但你可以做任何你想做的事情。
你可能还记得在Brendan Gregg的引言中,有一些关于修补HotSpot以保持RBP链的东西。也许HotSpot的Windows实现动态创建了WinDbg在x64上用于遍历堆栈的展开信息。也许它没有。我不知道。
在任何情况下,如果您使用的是相对较新的版本,则无需修补JVM。从JDK 8u60 build 19开始,此功能随-XX:+PreserveFramePointer
标志一起提供。
SOS知道如何解析内存中的CLR数据结构。我认为它并不需要CLR本身的帮助。这就是为什么你总是需要用于创建转储的CLR的确切SOS版本的原因。例如。
与此相反,JVMTI插件已加载到 JVM中。一旦你进入调试器,代理就无法做任何事情,假设它甚至被加载了。
perf-map-agent由一个小型Java程序(在他的repo中src/java/AttachOnce.java
)加载,获取有关当前JITted函数的信息及其相关信息。您可以执行相同操作,并在中断之前运行代理,或让代理始终工作并不断输出有关JITted方法的信息(如果您正在进行事后调试,例如Java和Java)过程是mostly dead)。在这种情况下,您必须对perf-map-agent代码进行一些更改。
如果您正在调试具有嵌入式JVM的应用程序(如Eclipse等;您不运行java.exe args ) ,您可能希望使用JAVA_TOOL_OPTIONS
环境变量,该变量允许您传递上述-XX:+PreserveFramePointer
或-agentlib
/ -agentpath
等参数,以便从头开始加载JVMTI代理附加到像pref-map-agent那样的正在运行的JVM上。
很抱歉,我无法为您提供一个工作工具,但是如果您确实需要,那么它似乎非常可行。除非在没有放松信息的情况下WinDbg无法完全堆叠,否则我不认为应该有任何特殊问题。
答案 1 :(得分:1)
使用jstack.exe
。这很直接。
C:\Users\conio\Desktop\code\JNA2>"C:\Program Files\Java\jdk1.8.0_102\bin\jstack.exe" -?
Usage:
jstack [-l] <pid>
(to connect to running process)
jstack -F [-m] [-l] <pid>
(to connect to a hung process)
jstack [-m] [-l] <executable> <core>
(to connect to a core file)
jstack [-m] [-l] [server_id@]<remote server IP or hostname>
(to connect to a remote debug server)
Options:
-F to force a thread dump. Use when jstack <pid> does not respond (process is hung)
-m to print both java and native frames (mixed mode)
-l long listing. Prints additional information about locks
-h or -help to print this help message
您希望使用-m
来获取Java堆栈和本机堆栈
如果你想从一个崩溃的进程中获取堆栈但是附加了一个事后调试器,你应该使用-F
标志。
例如,我有以下使用JNA的代码:
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
import com.sun.jna.Pointer;
public class Foo
{
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)Native.loadLibrary("msvcrt", CLibrary.class);
void printf(String format, Object... args);
Pointer malloc(int size);
Pointer memset(Pointer dest, int ch, int count);
void free(Pointer ptr);
}
public static void main(String[] args)
{
CLibrary.INSTANCE.printf("Hello, World\n");
Pointer buf = CLibrary.INSTANCE.malloc(2);
CLibrary.INSTANCE.memset(buf, 0, 0x20);
CLibrary.INSTANCE.free(buf);
CLibrary.INSTANCE.printf("Goodbye, Cruel World\n");
}
}
当我构建并执行此代码时,它崩溃并且WinDbg附加到它(因为它被设置为我的事后调试器)。
Microsoft (R) Windows Debugger Version 10.0.14321.1024 X86
Copyright (c) Microsoft Corporation. All rights reserved.
*** wait with pending attach
<<<snip>>>
(1f0.14d0): Unknown exception - code c0000374 (!!! second chance !!!)
eax=011eea00 ebx=77b5c908 ecx=00000001 edx=77b5c8d0 esi=00000002 edi=01251240
eip=77b29841 esp=011ee9dc ebp=011eea6c iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
ntdll!RtlReportCriticalFailure+0x89:
77b29841 eb33 jmp ntdll!RtlReportCriticalFailure+0xbe (77b29876)
0:003> !error c0000374
Error code: (NTSTATUS) 0xc0000374 (3221226356) - A heap has been corrupted.
0:003> k
# ChildEBP RetAddr
00 011eea6c 77b2cfe2 ntdll!RtlReportCriticalFailure+0x89
01 011eea78 77b2b763 ntdll!RtlpReportHeapFailure+0x32
02 011eea88 77ad16cf ntdll!RtlpHeapHandleError+0x1c
03 011eeab8 77ae278b ntdll!RtlpLogHeapFailure+0x9f
04 011eebc8 77a978aa ntdll!RtlpFreeHeap+0x4aa1b
05 011eebf4 749d77c5 ntdll!RtlFreeHeap+0xba
*** WARNING: Unable to verify checksum for C:\Users\conio\AppData\Local\Temp\jna-71761103\jna991038711348528033.dll
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Users\conio\AppData\Local\Temp\jna-71761103\jna991038711348528033.dll -
06 011eec40 6e562670 msvcrt!free+0x65
WARNING: Stack unwind information not available. Following frames may be wrong.
07 011eec4c 6e55d8e2 jna991038711348528033!Java_com_sun_jna_Native_setDetachState+0x7020
08 011eec88 6e553c74 jna991038711348528033!Java_com_sun_jna_Native_setDetachState+0x2292
09 011ef580 6e5548c4 jna991038711348528033!Java_com_sun_jna_Native_invokePointer+0xca4
0a 011ef5a8 02c4d3b3 jna991038711348528033!Java_com_sun_jna_Native_invokeVoid+0x24
0b 011ef5ec 02c44854 0x2c4d3b3
0c 011ef62c 02c447b4 0x2c44854
0d 011ef678 02c447b4 0x2c447b4
0e 011ef784 02c40697 0x2c447b4
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files (x86)\Java\jre1.8.0_102\bin\client\jvm.dll -
0f 011ef794 6e74a1b2 0x2c40697
10 011ef838 6e8104fe jvm!JVM_GetThreadStateNames+0x4cc82
*** ERROR: Module load completed but symbols could not be loaded for C:\Program Files (x86)\Java\jre1.8.0_102\bin\java.exe
11 011ef9bc 0083229e jvm!JVM_FindSignal+0x63b3e
12 011ef9d4 02b31310 java+0x229e
13 011ef9d8 02b31310 0x2b31310
14 011efa08 0083aeaf 0x2b31310
15 011efa40 0083af39 java+0xaeaf
16 011efa4c 751f62c4 java+0xaf39
17 011efa60 77ab0609 KERNEL32!BaseThreadInitThunk+0x24
18 011efaa8 77ab05d4 ntdll!__RtlUserThreadStart+0x2f
19 011efab8 00000000 ntdll!_RtlUserThreadStart+0x1b
0:003> |
. 0 id: 1f0 attach name: C:\Program Files (x86)\Java\jre1.8.0_102\bin\java.exe
0:003> ? 0x1f0
Evaluate expression: 496 = 000001f0
0:003> .dump /ma C:\Users\conio\Desktop\code\JNA2\Foo.dmp
Creating C:\Users\conio\Desktop\code\JNA2\Foo.dmp - mini user dump
Dump successfully written
执行jstack
:
C:\Users\conio\Desktop\code\JNA2>"C:\Program Files (x86)\Java\jdk1.8.0_102\bin\jstack.exe" -F -m 496
Attaching to process ID 496, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 25.102-b14
Deadlock Detection:
No deadlocks found.
----------------- 0 -----------------
<<<snip>>>
----------------- 3 -----------------
0x77b29841 ntdll!RtlpNtSetValueKey + 0x4e1
0x77b2cfe2 ntdll!RtlpNtSetValueKey + 0x3c82
0x77ad16cf ntdll!wcstok_s + 0x5baf
0x77ae278b ntdll!LdrSetAppCompatDllRedirectionCallback + 0xff2b
0x77a978aa ntdll!RtlFreeHeap + 0xba
0x749d77c5 msvcrt!free + 0x65
0x6e562670 jna991038711348528033!_Java_com_sun_jna_Native_setDetachState@20 + 0x7020
0x6e55d8e2 jna991038711348528033!_Java_com_sun_jna_Native_setDetachState@20 + 0x2292
0x6e553c74 jna991038711348528033!_Java_com_sun_jna_Native_invokePointer@24 + 0xca4
0x6e5548c4 jna991038711348528033!_Java_com_sun_jna_Native_invokeVoid@24 + 0x24
0x02c4d3b3 * com.sun.jna.Native.invokeVoid(long, int, java.lang.Object[]) bci:0 (Interpreted frame)
0x02c44854 * com.sun.jna.Function.invoke(java.lang.Object[], java.lang.Class, boolean) bci:29 line:374 (Interpreted frame)
0x02c447b4 * com.sun.jna.Function.invoke(java.lang.reflect.Method, java.lang.Class[], java.lang.Class, java.lang.Object[], java.util.Map) bci:249 line:323 (Interpreted frame)
0x02c447b4 * com.sun.jna.Library$Handler.invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) bci:348 line:236 (Interpreted frame)
0x02c447e9 * com.sun.proxy.$Proxy0.free(com.sun.jna.Pointer) bci:16 (Interpreted frame)
0x02c44889 * Foo.main(java.lang.String[]) bci:41 line:25 (Interpreted frame)
0x02c40697 <StubRoutines>
0x6e74a6e5 jvm!JVM_GetThreadStateNames + 0x4d1b5
0x6e8104fe jvm!_JVM_FindSignal@4 + 0x63b3e
0x6e74a77e jvm!JVM_GetThreadStateNames + 0x4d24e
0x6e6cc337 jvm!JNI_GetCreatedJavaVMs + 0x6f27
0x6e6d48cf jvm!JNI_GetCreatedJavaVMs + 0xf4bf
0x0083229e java + 0x229e
0x0083aeaf java + 0xaeaf
0x0083af39 java + 0xaf39
0x751f62c4 KERNEL32!BaseThreadInitThunk + 0x24
0x77ab0609 ntdll!RtlSubscribeWnfStateChangeNotification + 0x439
0x77ab05d4 ntdll!RtlSubscribeWnfStateChangeNotification + 0x404
----------------- 4 -----------------
<<<snip>>>
ntdll!RtlFreeHeap
上面的符号有些混乱,但它有效。
要将它与转储文件一起使用,您必须将正确的java.exe
二进制文件传递给它,以防您有多个版本,或者如果您在与生成转储的计算机不同的计算机上对其进行分析(类似于你需要SOS.dll
的版本来准确地使用用于转储的.NEt框架版本。)
C:\Users\conio\Desktop\code\JNA2>"C:\Program Files (x86)\Java\jdk1.8.0_102\bin\jstack.exe" -m "C:\Program Files (x86)\Java\jre1.8.0_102\bin\java.exe" Foo.dmp
Attaching to core Foo.dmp from executable C:\Program Files (x86)\Java\jre1.8.0_102\bin\java.exe, please wait...
Debugger attached successfully.
Client compiler detected.
JVM version is 25.102-b14
Deadlock Detection:
No deadlocks found.
<<<snip - same output as above>>
答案 2 :(得分:0)
您正在比较两件无法比较的事情。
一方面,您可以参考!DumpStack
这是调试器的插件。为特定操作系统编写调试器,在本例中是WinDbg for Windows。当然,Windows的调试器知道如何读取本机调用堆栈。
另一方面,您希望从JVM获取该信息。 JVM是Java虚拟机的缩写。如果您使用过像VMWare这样的虚拟机,那么您就知道虚拟机运行的是另一个操作系统&#34;。在这种情况下,操作系统的名称是Java。
如果您考虑在Windows主机上运行的Linux VM,并且在VM中使用Linux调试器(GDB),它是否会显示Windows调用堆栈?不,它不会 - 至少在VM设计正确的时候。
将其映射到JVM,您应该无法从Java程序中看到本机调用堆栈,因为它在VM中运行。
那么,为什么!DumpStack
可以呢?因为反过来说:当您在Windows主机上运行调试器时,您可以看到Linux VM的调用堆栈。与!DumpStack
相同:您从.NET VM外部运行它,它旨在解释.NET VM的内容。
所以,基本上你想要的是可以读取本机端的WinDbg以及可以解释Java VM(JVM)内容的WinDbg插件。这又是the question you have asked before,这被认为是偏离主题的,让我引用我的评论:
不幸的是,不,AFAIK没有这样的工具。
我在WinDbg业务中工作了7年,我找到了很多用于各种目的的插件,但是没有用于显示Java调用堆栈的插件。我很乐意看到一个,因为我有不止一个用例。