【问题标题】:async profiler displays wrong stacktraces异步探查器显示错误的堆栈跟踪
【发布时间】:2020-10-11 00:19:53
【问题描述】:

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

JVM 是 openjdk 版本“15-ea”2020-09-15,但同样发生在 openjdk 14.0.1 上。

异步分析器使用以下标志运行:-d 60 -t -i 10000 -o svg

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

【问题讨论】:

  • 虽然该问题缺乏可重复的示例(请尽可能添加),但问题的要点已被理解且有意义。我认为它不值得被否决/接近投票。
  • 您是在虚拟化环境中、在容器中还是在真实硬件上运行 Java?内核版本是多少?
  • 是的,它是 AWS EC2 中的 Ubuntu 虚拟机。我刚刚将内核更新为 5.8.0-050800-generic(如您的链接中所述),但重启后问题仍然存在。我会进一步挖掘。无论如何,它已经与异步分析器本身无关。
  • 非常感谢您的帮助!原来默认时钟源是xen。将其更改为 tsc 已解决此问题。我使用了这个指令,以防有人需要它。 aws.amazon.com/ru/premiumsupport/knowledge-center/…

标签: java jvm async-profiler


【解决方案1】:

我假设您想知道为什么配置文件中的clock_gettime 下面没有 Java 框架。

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

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

不幸的是,async-profiler 对此无能为力。一种可能的解决方法是禁用相应的 JVM 内在函数:

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

顺便说一句,我在你的火焰图中发现奇怪的是clock_gettime 调用了内核。通常它不应该,因为clock_gettime 是在映射到进程的用户空间的vDSO 中实现的。原因可能是时钟源错误/禁用了 vDSO(12)。

【讨论】:

  • 谢谢安德烈!禁用这些内在函数确实有助于使配置文件看起来合理。
猜你喜欢
  • 1970-01-01
  • 2011-08-12
  • 2014-01-24
  • 2018-09-19
  • 1970-01-01
  • 1970-01-01
  • 2021-02-25
  • 2018-02-21
  • 2010-10-16
相关资源
最近更新 更多