安全点是JVM为实现精确GC而设的线程暂停机制,确保线程停在栈和寄存器引用状态清晰、可达性可枚举的安全位置;若任意时刻强行中断,会导致引用漏标或误回收。

安全点(Safepoint)是 JVM 实现精确垃圾回收的关键机制,它让线程能在可预测、内存状态一致的位置被可靠暂停,从而支持 STW(Stop-The-World)阶段的 GC 操作。
为什么需要 Safepoint 而不是随时暂停?
Java 线程执行的是编译后的本地代码(JIT 编译后),指令流和 Java 栈帧、对象引用关系并不总是一一对应。如果在任意机器指令处强行挂起线程,JVM 无法准确判断哪些寄存器或栈位置存着有效的对象引用(比如某个寄存器正临时存放对象地址,但下一条指令就覆盖它),会导致 GC 漏标或误回收。Safepoint 就是预先选定的、语义明确的安全位置——在此处,所有对象引用的状态都是清晰且可达性可枚举的。
Safepoint 的常见触发位置
JVM 在编译或解释执行时,会在以下典型位置插入 Safepoint 检查(Safepoint Poll):
- 方法返回前(尤其是调用频繁的热点方法)
- 循环回边(loop back-edge),即每次跳转回循环开头时
- 方法调用前(特别是进入阻塞或 native 方法前)
- 抛异常、锁竞争失败等需进入 JVM 运行时处理的边界点
这些位置共同特点是:局部变量表、操作数栈、寄存器中活跃的引用已稳定,JVM 可以安全扫描当前栈帧并构建 OopMap(记录哪些位置存对象引用)。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
线程如何响应 Safepoint 请求?
当 GC 需要 STW 时,JVM 会设置全局标志位(如 safepoint_counter 变更)。各线程在执行到 Safepoint 检查点时,会主动读取该标志:
- 若检测到需进入 Safepoint,线程立即停止执行用户代码,保存上下文,转入 VM 状态等待 GC 完成
- 正在执行 native 方法、处于阻塞态(如 Object.wait())、或运行在解释器模式下的线程,可能不响应轮询,需通过其他机制(如 Handshake 或 Thread-Local Handshakes)协同暂停
- 长时间未到达 Safepoint 的线程(如纯计算大循环、无回边的 native 调用)会造成 Safepoint 耗时飙升,可通过 -XX:+PrintGCApplicationStoppedTime 和 -XX:+SafepointTimeout 排查
Safepoint 与 GC 的协作流程
一次典型的年轻代 GC(如 G1 Young GC)中 Safepoint 的作用如下:
- JVM 决定触发 GC,发起 Safepoint 请求
- 所有 Java 线程陆续运行到最近的 Safepoint 检查点并暂停
- VM 线程遍历每个 Java 线程栈,根据 OopMap 找出根集(GC Roots),包括栈上引用、静态字段、JNI 引用等
- 基于准确的根集启动并发或并行标记/复制阶段
- GC 完成后,清除 Safepoint 标志,各线程恢复执行
没有 Safepoint,JVM 就只能依赖保守式 GC(像早期 C++ 垃圾收集器那样猜引用),无法实现精确、低延迟、高吞吐的现代 GC 算法。

















