文章目录
什么是 SafePoint
SafePoint 是 Java 代码中的一个线程可能暂停执行的位置。SafePoint 保存了在其他位置没有的一些运行时信息。SafePoint 保存了线程上下文中的任何东西,包括对象,指向对象或非对象的内部指针。
在 JVM 处于 SafePoint 时,可以做什么呢?
- Garbage collection pauses
- Code deoptimization
- Flushing code cache
- Class redefinition (e.g. hot swap or instrumentation)
- Biased lock revocation
- Various debug operation (e.g. deadlock check or stacktrace dump)
在 JVM 源码的注释里提到,当系统要进入 SafePoint 时,不同状态的 Java 线程的暂停机制是不一样的:
- 运行状态的线程必须阻塞。
- 不与 JVM 交互的运行 Native Code 的线程能继续执行(如果需要通过 JNI 访问 Java 对象,调用 JAVA 方法,从 Native 回到 JAVA 的话,则必须等到 Safepoint 结束)。
- 所有阻塞中的线程,需要等待 SafePoint 结束,才能返回。
Java 线程是如何进入 SafePoint 的呢?
- 每个线程通过检查 SafePoint 数据结构的状态来确定是否需要暂停自己来进入安全态。
- 对于编译的代码,JIT 通过在代码中适当的位置插入 SafePoint 检查的代码(通常在调用的返回和循环的退出)。
- JIT 会在所有方法的返回之前,以及所有非 counted loop 的循环(无界循环)回跳之前放置一个 SafePoint,防止发生 GC 需要 STW 时,该线程一直不能暂停。
- 对于解释的代码,JVM 保存了两张字节码的执行表,如果需要进行 SafePoint 检查,JVM 会在两张表之间切换。
通常 safepoint 有三种状态:
- _not_synchronized:正常运行状态。
- _synchronizing:VM Thread 正在等待所有线程进入 safepoint。
- _synchronized:所有线程进入 safepoint,VM Thread 可以开始工作了。
程序运行时,可以设置 JVM 参数 -XX:+PrintSafepointStatistics –XX:PrintSafepointStatisticsCount=1 来输出 SafePoint 的统计信息。
源码分析
当 JVM 要让线程暂停 STW 时,会调用 SafepointSynchronize::begin 方法,该方法在 safepoint.cpp 里。源码地址