请解释JVM是如何收集ThreadDump不足的。
我不明白它是如何收集非CPU线程的堆栈跟踪(等待磁盘IO、网络、非自愿上下文切换)。
例如,linux perf只收集有关CPU线程(使用CPU周期)的信息。
发布于 2021-04-13 22:23:56
我将以HotSpot JVM为例。
JVM维护所有Java线程的列表:对于每个线程,它都有一个相应的VM结构。根据执行上下文的不同,线程可以处于下列状态之一(HotSpot知道每个线程的当前状态,因为它负责切换状态):
in_Java -线程正在执行Java代码,无论是在解释器中还是在JIT编译的方法中;in_vm -一个线程在VM运行时函数中;in_native -一个线程在JNI上下文中运行一个本机方法;非cpu线程只能有
in_native状态:所有套接字I/O、磁盘I/O和其他阻塞操作仅在本机代码中执行;in_vm状态,当线程在VM互斥对象上被阻塞时。每当JVM调用本机方法或获取竞争互斥对象时,它都会将最后一个Java指针存储到Thread结构中。
现在关键的部分是:HotSpot JVM只在 安全点上获得线程转储。
当您请求线程转储时,JVM请求停止世界暂停。处于in_Java状态的所有线程都会在最近的safepoint停止,在那里JVM知道如何遍历堆栈。
处于in_native状态的线程不会停止,但它们不需要停止。HotSpot知道它们的最后一个Java框架,因为指针存储在Thread结构中。JVM知道顶级Java框架,就可以找到它的调用者,然后找到调用者的调用者,依此类推。

这里重要的是,不管本机方法做什么,堆栈的Java部分都是“冻结”的。堆栈的顶部(本机)可以来回更改,而底层部分(Java)保持不变。它不能改变,因为JVM在从in_native到in_Java的每个开关上都检查挂起的safepoint操作:如果一个本机方法返回,并且VM当前正在运行停止世界操作,当前线程将一直阻塞直到操作结束。
因此,获取线程转储包括
in_Java和in_vm线程;https://stackoverflow.com/questions/67080990
复制相似问题