安全点是线程执行中引用关系稳定、可被jvm安全暂停的指令边界,用于保障gc roots枚举准确;安全区域则覆盖sleep/wait/blocked等非运行态,确保所有线程在stw时均处于可预测状态。

垃圾回收器不能在任意时刻暂停线程执行 GC,必须等线程到达某些可控、状态确定的位置——这就是安全点;而当线程不运行(如 sleep、wait、blocked)时,它无法主动走到安全点,这时就需要安全区域来兜底。
安全点:线程执行中可安全暂停的位置
安全点不是代码里的“断点”,而是 JVM 预先选定的、引用关系稳定且易于识别的指令边界。它的核心作用是让所有活跃线程能快速、统一地停顿下来,保证 GC Roots 枚举的准确性。
- 典型位置包括:方法返回前、方法调用后、循环末尾、异常跳转目标处——这些地方通常伴随较长执行路径或上下文切换,天然适合插入检查逻辑
- 安全点不能太密:否则频繁轮询标志位会增加开销,OopMap 数据也会膨胀
- 安全点不能太少:否则 GC 等待时间过长,STW 延迟不可控
- HotSpot 使用主动式中断:JVM 设置全局中断标志,线程在到达安全点时自行检查该标志,为真则挂起自身
安全区域:覆盖非运行态线程的“安全窗口”
当线程处于阻塞、睡眠或等待锁状态时,它无法响应中断、也无法主动执行到安全点。安全区域正是为这类场景设计的——它是一段引用关系完全冻结的代码区间,进入后即视为“已就绪”,无需再移动。
- 常见场景:Object.wait()、Thread.sleep()、LockSupport.park()、IO 阻塞调用等入口处会被标记为安全区域起点
- 线程进入时设置标识,表明“当前状态不会改变对象图”,JVM 可忽略它直接开始 GC
- 线程准备离开该区域前,必须检查 GC 是否已完成;未完成则等待信号,避免在引用关系重建过程中退出
- 本质上,安全区域是安全点在“静止态”下的延伸,两者共同保障所有线程在 GC 时都处于可预测、无副作用的状态
为什么不能每行都设安全点?
理论上可以,但代价极高。每条指令都生成 OopMap 会占用大量内存;每次执行都轮询中断标志会拖慢吞吐。JVM 选择在复用度高、耗时明显的位置设点,既满足 STW 可控性,又把运行时开销压到最低。
安全点和安全区域不是开发者手动配置的参数,而是 HotSpot 在编译期和运行期自动识别并注入的机制。你不需要写代码去“加安全点”,但理解它们有助于分析 GC 停顿原因——比如某段 native 调用或长时间空循环,可能迟迟不进入安全点,导致 GC 等待超时。











