1.JDK VM.Thread里的 Safepoint机制

JDK VM.Thread 各种循环与Safepoint GC STW 相关问题 专题文章列表
1.JDK VM.Thread里的 Safepoint机制
2.JVM JIT区分非可数循环与可数循环
3.JVM 区分非可数循环与可数循环 JIT编译器省略Safepoint检查,导致该线程无法进入Safepoint,而阻塞VM Thread和其他所有线程
4.调整JVM参数或规范编码规避GC判定线程无Safepoint导致的STW问题

1.JDK VM.Thread里的 Safepoint机制

在 JDK 8 中,VM Thread 是 JVM 内部的一个重要线程,负责执行各种“VM 操作”(VM Operations),比如垃圾回收(GC)、类加载、线程堆栈 dump、偏向锁撤销等。这些操作通常需要“全局一致性”状态,因此必须在所有 Java 线程到达一个安全点(Safepoint)时才能执行。


一、什么是 Safepoint(安全点)?

Safepoint 是 JVM 中的一个机制,用来确保所有 Java 线程在执行某些 VM 操作前,都处于一个“可被安全暂停”的状态。

在 Safepoint,每个线程的执行状态是已知的,JVM 可以安全地操作堆、元空间、线程栈等,而不会破坏对象图或导致数据不一致。


二、为什么需要 Safepoint?

JVM 的很多操作(如 GC)需要“Stop-The-World”(STW),即暂停所有 Java 线程。但不能在任意位置暂停线程,否则可能:

  • 正在修改对象引用,导致对象图不一致
  • 执行到一半的字节码指令,状态不完整
  • 锁状态不一致

因此,JVM 会等待所有线程到达“安全点”后再执行这些操作。


三、VM Thread 与 Safepoint 的关系

VM Thread 是执行这些需要 Safepoint 的操作的线程。它不会主动执行 GC 或其他任务,而是从“VM Operation Queue”中取出任务,并在所有线程到达 Safepoint 后执行。

VM Thread 的典型行为:
  1. 收到一个 VM 操作请求(如 VM_GC_Operation
  2. 请求进入 VM Operation 队列
  3. VM Thread 开始处理该请求
  4. 触发 Safepoint 检查:通知所有 Java 线程进入 Safepoint
  5. 等待所有线程响应并到达 Safepoint
  6. 执行 VM 操作(如 GC)
  7. 恢复所有线程运行

四、Safepoint 是如何实现的?(JDK 8)

在 JDK 8 中,Safepoint 的实现基于“轮询机制”:

1. Safepoint Polling(轮询)

JVM 在生成的代码中插入Safepoint 检查点(通常是循环末尾、方法返回前、方法调用前等):

test %rax, %rax
jne <safepoint_handler>

这行汇编代码实际上是在检查一个全局的“Safepoint 标志”(Poll_PageSafepoint Poll)。如果 JVM 设置了该标志(表示需要进入 Safepoint),线程就会跳转到 Safepoint 处理逻辑。

这个标志通常通过“内存页保护”或“内存映射页”来实现。例如:让某个内存页不可读,当线程访问它时触发 SIGSEGV,JVM 捕获信号并处理为进入 Safepoint。

2. Safepoint 的触发方式
  • GC 触发
  • biased lock revocation
  • 线程 dump
  • JIT 去优化(deoptimization)
  • Class 操作(如 redefine class)
3. 线程如何进入 Safepoint?
  • 解释执行的线程:在字节码解释器中定期检查
  • JIT 编译的代码:在生成的机器码中插入 Safepoint Poll
  • Native 线程:不能立即进入 Safepoint,必须等到它们返回 Java 代码(_thread_in_native_thread_in_Java

Native 线程无法被强制中断,因此可能造成 Safepoint 延迟(常见性能问题)


五、如何监控 Safepoint?

JDK 8 提供了以下 JVM 参数来监控 Safepoint:

-XX:+PrintSafepointStatistics
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCApplicationConcurrentTime
-XX:+UnlockDiagnosticVMOptions

输出示例:

VM Operation [GC pause (G1 Evacuation Pause)]
Safepoint "GC", Safepoint::do_cleanup_tasks()
Total time for which application threads were stopped: 0.0123456 secs

你还可以通过:

jcmd <pid> VM.safepoint

查看当前 Safepoint 状态。


六、Safepoint 常见问题
1. Safepoint 迟迟无法进入

原因:

  • 有线程长时间运行在 Native 状态(如 JNI 调用、sleep、IO)
  • 线程在执行没有 Safepoint Poll 的长循环(JIT 优化后可能移除 Poll)

解决:

  • 使用 -XX:GuaranteedSafepointInterval=300000(每 5 分钟强制 Safepoint)
  • 避免长时间 JNI 调用
  • 使用 jstack 查看哪些线程未进入 Safepoint
2. STW 时间过长

可能是因为:

  • GC 停顿
  • 偏向锁批量撤销(Biased Lock Revocation)
  • JIT 去优化

七、Safepoint 与 Stop-The-World(STW)
  • 所有 Safepoint 操作都会导致 STW
  • STW 时间 = 等待所有线程进入 Safepoint 的时间 + VM 操作执行时间
  • 有时“进入 Safepoint”的时间比 GC 本身还长(特别是有线程卡在 Native)

总结
概念 说明
VM Thread 执行 VM 操作的后台线程
Safepoint 所有线程必须到达的安全位置,用于执行 STW 操作
Safepoint Polling 在代码中插入检查,判断是否需要进入 Safepoint
进入条件 循环、方法调用、异常处理等位置
Native 线程 无法立即响应,可能导致 Safepoint 延迟
监控工具 jcmd, -XX:+PrintSafepointStatistics, GC 日志
哪些版本JDK有VM Thread

几乎所有现代版本的 JDK(包括 JDK 8、JDK 11、JDK 17、JDK 21 等)都包含 VM Thread,它是 HotSpot JVM 的核心组成部分之一,用于执行需要全局一致性的“VM 操作”。


✅ 八、VM Thread 的存在范围
JDK 版本 是否有 VM Thread 说明
JDK 8 ✅ 是 经典的 VM Thread 实现
JDK 9 ✅ 是 模块化,但 VM Thread 保留
JDK 11 ✅ 是 长期支持版(LTS),VM Thread 仍在
JDK 17 ✅ 是 LTS 版本,VM Thread 依然存在
JDK 21 ✅ 是 最新 LTS,VM Thread 仍然关键
OpenJDK / Oracle JDK ✅ 都有 所有基于 HotSpot 的 JVM 都有

🔹 结论:只要使用的是 HotSpot JVM,无论哪个 JDK 版本,都会有 VM Thread


✅ 九、VM Thread 的作用在各版本中基本一致

VM Thread 的职责在 JDK 8 到 JDK 21 中基本保持不变,主要负责:

功能 说明
执行 GC 操作 如 G1、ZGC(部分阶段)、CMS、Parallel GC 的 STW 阶段
偏向锁撤销(Biased Lock Revocation) JDK 15+ 默认禁用,但仍支持
类重定义(JVM TI, redefine classes) 调试、热更新(如 HotSwap)
线程 dump / 堆 dump jstack, jmap 等工具触发的操作
去优化(Deoptimization) JIT 回退到解释执行
Safepoint 协调 等待所有线程进入 Safepoint

✅ 十、不同 JDK 版本中的变化(VM Thread 的演进)

虽然 VM Thread 一直存在,但随着 JVM 的演进,它的使用频率和重要性有所下降,尤其是在低延迟 GC 出现后。

1. JDK 11+:ZGC 和 Shenandoah 的引入
  • ZGC(JDK 11+ 实验,JDK 15+ 生产可用)
  • Shenandoah(JDK 12+)
  • 这些 GC 的 大部分操作是并发的,不再依赖 VM Thread 执行 STW 操作
  • 某些操作仍需 VM Thread,如:
    • 初始标记(Initial Mark)
    • 最终标记(Final Mark)
    • 引用处理
    • 类卸载

⚠️ 即使是 ZGC,仍然需要 Safepoint 和 VM Thread 来执行这些短暂停顿操作

2. JDK 15:默认禁用偏向锁(Biased Locking)
  • 偏向锁撤销是 VM Thread 的重负载操作
  • JDK 15 起默认禁用(-XX:-UseBiasedLocking
  • 减少了 VM Thread 的工作量,降低 Safepoint 延迟
3. JDK 18:删除永久代(PermGen),元空间(Metaspace)
  • 类加载/卸载机制变化,但 VM Thread 仍参与类元数据清理
4. JDK 21:虚拟线程(Virtual Threads)
  • 虚拟线程(Project Loom)大量使用 Carrier Thread(平台线程)
  • VM Thread 仍然存在,用于底层 VM 操作
  • 虚拟线程不会改变 Safepoint 和 VM Thread 的底层机制

✅ 十一、如何验证 VM Thread 存在?

你可以通过以下方式查看:

1. 使用 jstack 查看线程
jstack <pid> | grep "VM Thread"

输出示例:

"VM Thread" os_prio=0 tid=0x00007f8c8c00a000 nid=0x1a4b runnable
2. 使用 jcmd 查看 Safepoint
jcmd <pid> VM.safepoint
3. 启用 Safepoint 日志
-XX:+PrintSafepointStatistics -XX:+PrintGCApplicationStoppedTime

✅ 十二、有没有 JVM 没有 VM Thread?

极少数非 HotSpot 的 JVM 实现可能没有“单一 VM Thread”,例如:

JVM 实现 是否有 VM Thread
HotSpot (Oracle/OpenJDK) ✅ 有
OpenJ9 (IBM) ❌ 无(使用不同机制)
GraalVM Native Image ❌ 无(AOT 编译,无运行时 VM Thread)
Azul Zing ✅ 有,但实现不同(C4 GC 并发性强)

🔹 所以:VM Thread 是 HotSpot 特有的设计,不是所有 JVM 都有。


✅ 总结
问题 回答
JDK 8 之后还有 VM Thread 吗? ✅ 有,一直到 JDK 21 都存在
VM Thread 的作用变了吗? 基本不变,但使用频率降低(因并发 GC)
ZGC / 虚拟线程会取代 VM Thread 吗? ❌ 不会,它仍是底层基础设施
哪些 JVM 没有 VM Thread? OpenJ9、GraalVM Native Image 等非 HotSpot 实现
posted @ 2025-02-27 14:57  Journey&Flower  阅读(17)  评论(0)    收藏  举报