为什么 HotSpot ExecutionSample 事件总是 return STATE_RUNNABLE?
Why does the HotSpot ExecutionSample event always return STATE_RUNNABLE?
我在 OpenJDK11 中使用来自 HotSpot 的 ExecutionSample event。
它有一个线程状态字段,但我只看到该字段的一个值:STATE_RUNNABLE
HotSpot 如何选择对哪些线程进行采样?为什么它们总是可以运行?
Kotlin 中的简单复制代码:
import jdk.jfr.Recording
import jdk.jfr.consumer.RecordingFile
import java.nio.file.Path
object ExecutionSampleTest {
private const val EXECUTION_SAMPLE = "jdk.ExecutionSample"
private val RECORDING_PATH = Path.of("/tmp/recording.jfr")
@JvmStatic
fun main(args: Array<String>) {
Recording().use { recording ->
recording.enable(EXECUTION_SAMPLE)
recording.settings = recording.settings.plus("$EXECUTION_SAMPLE#period" to "1 ms")
recording.start()
repeat(100) {
// start some sleeping threads, just so we've got something to sample
Thread { Thread.sleep(20_000) }.start()
}
Thread.sleep(20_000)
recording.stop()
recording.dump(RECORDING_PATH)
RecordingFile.readAllEvents(RECORDING_PATH).forEach {
println("Thread state: ${it.getString("state")}")
}
}
}
}
只打印:Thread state: STATE_RUNNABLE
Why does the HotSpot ExecutionSample event always return STATE_RUNNABLE?
按设计。
JFR 方法探查器定期对 Java 线程进行采样并生成两种类型的事件:
ExecutionSample
,当线程状态为in_java
NativeMethodSample
,当线程状态为in_native
查看jfrThreadSampler.cpp源代码:
if (JAVA_SAMPLE == type) {
if (thread_state_in_java(thread)) {
ret = sample_thread_in_java(thread, frames, max_frames);
}
} else {
assert(NATIVE_SAMPLE == type, "invariant");
if (thread_state_in_native(thread)) {
ret = sample_thread_in_native(thread, frames, max_frames);
}
}
in_java
和in_native
都对应JFR格式的STATE_RUNNABLE
当一个线程由于任一原因(STATE_SLEEPING
、STATE_PARKED
等)而不 运行 可用时,其 JVM 状态为 thread_blocked
。但是,JFR 方法分析器根本不对阻塞的线程进行采样。
如果您对挂钟分析感兴趣(即采样 所有 线程,无论它们 运行 在 CPU 还是睡眠),您可能想要看看 async-profiler。 Async-profiler 还可以生成 JFR 兼容格式的输出,但与 JFR 不同的是,它会为 RUNNABLE 和 IDLE 线程生成 ExecutionSample
个事件。
我在 OpenJDK11 中使用来自 HotSpot 的 ExecutionSample event。
它有一个线程状态字段,但我只看到该字段的一个值:STATE_RUNNABLE
HotSpot 如何选择对哪些线程进行采样?为什么它们总是可以运行?
Kotlin 中的简单复制代码:
import jdk.jfr.Recording
import jdk.jfr.consumer.RecordingFile
import java.nio.file.Path
object ExecutionSampleTest {
private const val EXECUTION_SAMPLE = "jdk.ExecutionSample"
private val RECORDING_PATH = Path.of("/tmp/recording.jfr")
@JvmStatic
fun main(args: Array<String>) {
Recording().use { recording ->
recording.enable(EXECUTION_SAMPLE)
recording.settings = recording.settings.plus("$EXECUTION_SAMPLE#period" to "1 ms")
recording.start()
repeat(100) {
// start some sleeping threads, just so we've got something to sample
Thread { Thread.sleep(20_000) }.start()
}
Thread.sleep(20_000)
recording.stop()
recording.dump(RECORDING_PATH)
RecordingFile.readAllEvents(RECORDING_PATH).forEach {
println("Thread state: ${it.getString("state")}")
}
}
}
}
只打印:Thread state: STATE_RUNNABLE
Why does the HotSpot ExecutionSample event always return STATE_RUNNABLE?
按设计。
JFR 方法探查器定期对 Java 线程进行采样并生成两种类型的事件:
ExecutionSample
,当线程状态为in_java
NativeMethodSample
,当线程状态为in_native
查看jfrThreadSampler.cpp源代码:
if (JAVA_SAMPLE == type) {
if (thread_state_in_java(thread)) {
ret = sample_thread_in_java(thread, frames, max_frames);
}
} else {
assert(NATIVE_SAMPLE == type, "invariant");
if (thread_state_in_native(thread)) {
ret = sample_thread_in_native(thread, frames, max_frames);
}
}
in_java
和in_native
都对应JFR格式的STATE_RUNNABLE
当一个线程由于任一原因(STATE_SLEEPING
、STATE_PARKED
等)而不 运行 可用时,其 JVM 状态为 thread_blocked
。但是,JFR 方法分析器根本不对阻塞的线程进行采样。
如果您对挂钟分析感兴趣(即采样 所有 线程,无论它们 运行 在 CPU 还是睡眠),您可能想要看看 async-profiler。 Async-profiler 还可以生成 JFR 兼容格式的输出,但与 JFR 不同的是,它会为 RUNNABLE 和 IDLE 线程生成 ExecutionSample
个事件。