Java 异步探查器显示错误的堆栈跟踪

Java 异步探查器显示错误的堆栈跟踪,java,jvm,async-profiler,Java,Jvm,Async Profiler,我正在尝试使用v.1.8.1来分析我的应用程序 JVM是openjdk版本“15 ea”2020-09-15,但openjdk 14.0.1也是如此 异步探查器使用以下标志运行:-D60-t-I10000-OSSVG 它显示出非常奇怪的结果。我们可以看到,硬件线程大部分时间不是在java.lang.thread::run中,而是在一些奇怪的地方。怎么解释呢?我看到了一种可能的解释,异步探查器无法正确遍历堆栈跟踪,并将这些堆栈跟踪的一部分放在错误的位置。还有别的解释吗?如何修复它呢?我想您可能会想

我正在尝试使用v.1.8.1来分析我的应用程序

JVM是openjdk版本“15 ea”2020-09-15,但openjdk 14.0.1也是如此

异步探查器使用以下标志运行:-D60-t-I10000-OSSVG


它显示出非常奇怪的结果。我们可以看到,硬件线程大部分时间不是在java.lang.thread::run中,而是在一些奇怪的地方。怎么解释呢?我看到了一种可能的解释,异步探查器无法正确遍历堆栈跟踪,并将这些堆栈跟踪的一部分放在错误的位置。还有别的解释吗?如何修复它呢?

我想您可能会想知道为什么配置文件中的
clock\u gettime
下面没有Java帧

如您所见,堆栈以
[unknown\u Java]
帧结束。这意味着,线程确实运行了一些Java代码,但async profiler无法获取Java堆栈跟踪,因为JVM无法找到顶部Java帧

这是因为
System.nanoTime()
System.currentTimeMillis()
是JVM的内部函数。它们被JIT编译为对应C函数的直接调用,而无需将线程从java中的
切换到本地
状态的
。这意味着,JVM在调用
nanoTime
currentTimeMillis
时不会保存指向最后一个Java帧的指针,因此在异步堆栈遍历期间发现最后一个Java帧时会出现问题

不幸的是,异步探查器对此无能为力。一种可能的解决方法是禁用相应的JVM内部函数:

java -XX:+UnlockDiagnosticVMOptions -XX:DisableIntrinsic=_currentTimeMillis,_nanoTime

顺便说一句,我在flame图中发现奇怪的是,
clock\u gettime
调用内核。通常不应该这样做,因为
clock\u gettime
是在映射到进程的用户空间中实现的。原因可能是错误的时钟源/禁用的vDSO(,)。

尽管问题缺少可复制的示例(如果可能,请添加),但问题的要点已被理解并有意义。我认为它不值得投反对票/反对票。您是在虚拟化环境中、容器中还是在真正的硬件上运行Java?内核版本是什么?是的,它是AWS EC2中的Ubuntu虚拟机。我刚刚将内核更新为5.8.0-050800-generic(如链接中所建议的),但重新启动后问题仍然存在。我会进一步挖掘。无论如何,它本身与异步探查器无关。非常感谢您的帮助!结果是默认的时钟源是xen。将其更改为tsc已修复该问题。我用了这个指令,以防有人需要。谢谢你,安德烈!禁用这些内在功能确实有助于使配置文件看起来合理。