Java Safepoint 与Stop The World

本文详细介绍了Java中的Safepoint机制及其工作原理,解释了Safepoint如何确保线程在安全点上能被正确操作。同时,文章深入探讨了Stop The World现象,即JVM等待所有线程进入Safepoint并暂停,以执行全局操作,如垃圾收集、代码优化等。此外,文中还分析了Stop The World的四个阶段,并提供了相关参数以监控和优化STW事件。

。原文首发于知乎https://www.zhihu.com/question/57722838

1 SafePoint

1.1 什么是SafePoint

Safepoint是java代码中一个线程可能暂停执行的一个位置,SafePoint保存了其他位置没有的一些运行信息。在这个位置上保存了线程上下文的任何信息,包括对象或者非对象的内部指针。在接收到JVM的进入Stop The World 的信息,在safepoint上,用户线程会被挂起。如果JNI代码想要访问在安全点上的用户线程,那么JNI所在线程也会阻塞直到用户线程离开安全点。因为在安全点上jvm线程信息被很好的描述,所以特别适合做一些全局性的操作,例如代码反优化,线程快照等等。http://peg.hengtiansoft.com/article/jvm-zhong-de-safepoint/

1.2 Safepoint是如何工作的?

在HotSpot虚拟机中,safepoint 协议是主动协作的 。每一个用户线程在安全点 上都会检测一个标志位,来决定自己是否暂停执行。

对于JIT编译后的代码,JIT会在代码特定的位置(通常来说,在方法的返回处和counted loop的结束处)上插入安全点代码。对于解释执行的代码,JVM会设置一个2字节的dispatch tables,解释器执行的时候会经常去检查这个dispatch tables,当有safepoint请求的时候,就会让线程去进行safepoint检查。

1.3 Safepoint的相关总结

翻译自: http://chriskirk.blogspot.com/2013/09/what-is-java-safepoint.html

  • 一个线程可以在SafePoint上,也可以不在SafePoint上。一个线程在SafePoint时,它的状态可以安全地其他JVM线程所操作和观测;不在SafePoint时,就不能。
  • 在SafePoint上不代表被阻塞(比如:JNI方法就可以在SafePoint上运行),但是被阻塞一定发生在SafePoint上。
  • 当JVM决定达到一个全局的SafePoint(也叫做Stop the
    World),JVM里面所有的线程都要在SafePoint上并且不能离开,直到JVM让线程允许为止。这对要求所有线程都要被良好的描述的操作(比如CG,代码反优化等等)非常有好处。
  • 一些JVM可以持有一些私有的线程到SafePoint上而不需要全局的SafePoint,比如Zing.
  • 当你写一些非安全的代码的时候,你必须假设SafePoint有可能发生在任何两个字节码之间。
  • 非安全代码的调用并不要求必须有安全点,但是他们可以包含一个或者多个安全点。
  • 所有类型的JVM有一些效率非常高的技巧和去快速的穿过SafePoint,线程并不需要真正地进入SafePoint除非虚拟机指示线程这么做。
  • 所有的JNI方法都在SafePoint上执行。在安全点,JNI代码都不能改变和观测发起调用JNI代码线程的java机器状态。任何通过JNI
    API改变和观测调用线程的状态必须在调用线程离开安全点之后,以及再次进入SafePoint之前的时间内发生。

想了解SafePoint源码的同学,请参照这里:

### 什么是 Stop-The-World? **Stop-The-World(STW)** 是 Java 虚拟机(JVM)在执行某些关键操作(如垃圾回收、类加载、偏向锁撤销等)时,**暂停所有用户线程(即应用程序线程)** 的行为。在此期间,除了 JVM 系统线程(如 GC 线程)外,所有 Java 应用线程都将停止运行。 STW 是为了保证 JVM 在执行这些操作时内存状态的一致性而采取的机制。 --- ### Stop-The-World 的常见触发场景 | 操作 | 触发 STW | |------|----------| | Minor GC(新生代 GC) | ✅ | | Full GC(老年代 + 新生代 + 元空间 GC) | ✅ | | 类加载(首次使用类) | ✅ | | 偏向锁撤销(Biased Lock Revocation) | ✅ | | 线程 Dump、堆 Dump | ✅ | | JVM 安全点(Safepoint)操作 | ✅ | | JNI 调用 | ❌(部分操作) | --- ### Stop-The-WorldJava 应用的影响 #### 1. **响应时间变长** - STW 期间所有应用线程暂停,接口响应时间会突增。 - 对延迟敏感的应用(如金融交易、实时系统)影响尤为明显。 #### 2. **吞吐量下降** - GC 等操作占用了 CPU 时间,实际用于处理业务逻辑的时间减少。 - 频繁的 STW 导致整体吞吐量下降。 #### 3. **系统抖动** - GC 暂停时间不稳定,导致应用响应时间波动大。 - 可能引发服务降级、熔断、重试等连锁反应。 #### 4. **分布式系统故障** - 如果某个节点在选举、心跳检测等关键路径上发生长时间 STW,可能被误判为宕机。 - 导致集群重新选举、数据迁移等开销。 #### 5. **用户体验受损** - Web 应用可能出现页面加载缓慢、接口超时、页面空白等问题。 --- ### 如何查看 Stop-The-World 的发生? #### 1. **GC 日志分析** 启用 GC 日志后,可以看到每次 GC 的耗时和 STW 时间。 ```bash -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:gc.log ``` 示例日志: ```text 2025-04-05T10:00:00.123+0800: [GC (Allocation Failure) [PSYoungGen: 102400K->10240K(102400K)] 150000K->110000K(307200K), 0.0500000 secs] [Times: user=0.05 sys=0.00, real=0.05 secs] ``` - `real=0.05 secs` 表示 STW 时间为 50ms。 #### 2. **使用 JFR(Java Flight Recorder)** JFR 可以记录详细的 GC 暂停事件、Safepoint 事件等。 ```bash java -XX:+FlightRecorder -XX:StartFlightRecording=duration=60s,filename=myrecording.jfr -jar app.jar ``` 在 JFR 分析工具中可以看到: - 每次 Safepoint 暂停的时间 - GC 暂停时间 - 偏向锁撤销时间等 #### 3. **使用 JVisualVM 或 Arthas** - 实时查看线程暂停、GC 次数、GC 时间等。 --- ### 如何减少 Stop-The-World 的影响? #### 1. **选择低延迟的垃圾回收器** - **G1 GC**:可预测的停顿时间模型,适用于大堆内存。 - **ZGC / Shenandoah GC**:亚毫秒级停顿,适合对延迟敏感的系统。 ```bash java -XX:+UseZGC -jar app.jar ``` #### 2. **合理设置堆大小** - 避免堆太小导致频繁 GC。 - 避免堆太大导致单次 GC 时间过长。 ```bash java -Xms4g -Xmx4g -jar app.jar ``` #### 3. **避免频繁 Full GC** - 减少 System.gc() 调用。 - 避免内存泄漏。 - 使用缓存减少对象创建。 #### 4. **减少对象分配** - 使用对象池、缓存机制。 - 减少临时对象的创建(如在循环中创建对象)。 #### 5. **避免偏向锁撤销** - 可以关闭偏向锁(Java 15+ 默认关闭): ```bash -XX:-UseBiasedLocking ``` --- ### 示例代码:查看 GC 暂停时间 ```java import java.lang.management.GarbageCollectorMXBean; import java.util.List; import java.lang.management.ManagementFactory; public class STWMonitor { public static void main(String[] args) { List<GarbageCollectorMXBean> gcBeans = ManagementFactory.getGarbageCollectorMXBeans(); for (GarbageCollectorMXBean gc : gcBeans) { System.out.println("GC Name: " + gc.getName() + ", Count: " + gc.getCollectionCount()); } } } ``` --- ###
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值