gpt4 book ai didi

java - JVM 如何收集 ThreadDump 底层

转载 作者:行者123 更新时间:2023-12-05 01:30:24 27 4
gpt4 key购买 nike

请解释 JVM 是如何在底层收集 ThreadDump 的。
我不明白它如何收集脱离 CPU 的线程的堆栈跟踪(等待磁盘 IO、网络、非自愿上下文切换)。
例如,linux perf 仅收集有关 on-CPU 线程(使用 CPU 周期)的信息

最佳答案

我将以 HotSpot JVM 为例。

JVM 维护所有 Java 线程的列表:对于每个线程,它都有一个对应的 VM 结构。线程可以根据其执行上下文处于以下状态之一(HotSpot 知道每个线程的当前状态,因为它负责切换状态):

  • in_Java - 一个线程在解释器或 JIT 编译方法中执行 Java 代码;
  • in_vm - 线程在 VM 运行时函数内;
  • in_native - 线程正在 JNI 上下文中运行 native 方法;
  • 还有过渡状态,但为简单起见,我们跳过它们。

一个off-cpu线程只能有

  • in_native 状态:所有套接字 I/O、磁盘 I/O 和其他阻塞操作仅在 native 代码中执行;
  • in_vm 状态,当线程在 VM 互斥体上被阻塞时。

每当 JVM 调用 native 方法或获取争用的互斥量时,它会将最后一个 Java 帧指针存储到 Thread 结构中。

现在是关键部分:HotSpot JVM 仅在 safepoint 处获取线程转储.

当您请求线程转储时,JVM 请求停止世界暂停。 in_Java 状态下的所有线程都停止在最近的安全点,JVM 知道如何遍历堆栈。

处于 in_native 状态的线程不会停止,但它们也不需要。 HotSpot 知道它们的最后一个 Java 帧,因为指针存储在 Thread 结构中。知道顶层 Java 框架后,JVM 可以找到它的调用者,然后是调用者的调用者,依此类推。

Stack walking

这里重要的是堆栈的 Java 部分是“卡住的”,无论 native 方法做什么。堆栈的顶部( native )可以来回更改,而底部(Java)保持不变。它不能改变,因为 JVM 在每次从 in_native 切换到 in_Java 时检查挂起的安全点操作:如果 native 方法返回,并且 VM 当前正在运行停止- the-world 操作,当前线程阻塞直到操作结束。

因此,获取线程转储涉及

  1. 在安全点停止所有 in_Javain_vm 线程;
  2. 遍历由 JVM 维护的全局线程列表;
  3. 如果一个线程正在运行本地方法,它的顶级Java框架存储在一个线程结构中;如果一个线程正在运行 Java 代码,它的顶部框架对应于当前正在执行的 Java 方法。
  4. 每个框架都有到前一框架的链接,因此给定顶层框架,JVM 可以构建到底部的整个堆栈跟踪。

关于java - JVM 如何收集 ThreadDump 底层,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67080990/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com