JVM 安全点 Safepoint

最近在看 ZGC 的某些具体的实现, 有篇文章对了从 Serial GC, 到 parallel GC, 再到CMS, 然后到G1, 最后到如今的ZGC, 其中一个重要的差别就是把很多GC 时间(STOP the world)要做的事情移到并发去做的过程. 其实这是一个从简单到复杂的过程, 也是一个从粗放到逐步精细控制的过程. 最终的结果就是在GC的时间点上, 做的事情越来越少.

如果讨论到GC 的时间点, 其中一个重要的事情, 就是安全点(Safepoint), 它是一个让所有业务线程在某个点全部停下来的过程, 由于有很多业务线程, 让它们同时停下来, 就涉及到一个协调机制, 如何让这些线程在不影响业务线程的情况下, 以最快的速度停下来, 就显得非常重要.

什么是JVM Safepoint

JVM(Java虚拟机)中的Safepoint是一种机制,用于确保所有线程在执行某些特定的系统级操作之前达到一个已知且一致的状态。这些系统级操作通常包括垃圾收集(GC)、线程栈的展开、代码重优化以及一些运行时系统的更新等。

在Safepoint期间,JVM会暂停所有的Java线程执行(也就是所谓的“Stop-The-World”暂停),直到所有线程都到达Safepoint。这样可以确保在进行这些操作时,不会有任何线程在执行Java字节码,从而避免了潜在的数据不一致和竞争条件。

JVM 可以在那些代码区域达到安全点?

  1. 方法调用边界:当一个方法被调用时,可能会在调用前后插入Safepoint检查。这是因为方法调用是程序执行中的自然中断点,且通常是执行时间较长的操作。
  2. 循环回边:在循环结构中,循环的末尾(即循环要重新开始的地方)是达到Safepoint的一个常见位置。这样做是为了防止长时间运行的循环阻止系统达到Safepoint。
  3. 显式的Safepoint检查点:JVM的即时编译器(JIT)可能会在生成的机器代码中的特定位置插入显式的Safepoint检查。这些检查通常会在执行时间较长的代码段中进行。
  4. 同步操作:当线程尝试进入或退出同步块(synchronized block)或方法时,也可能会进行Safepoint检查,因为这些操作涉及到锁的获取和释放。
  5. 异常抛出点:当程序抛出异常时,可能会在异常处理之前达到Safepoint,因为异常处理涉及到栈的展开和控制流的改变。
  6. 线程状态变化:当线程状态发生变化时(例如,从运行状态转为等待或休眠状态),也可能会进行Safepoint检查。

其他:JVM实现还可能在其他不那么明显的地方插入Safepoint检查,这些通常是由于特定的实现细节和优化策略。

其它

  1. Safepoint 在 Java 语言规范里没有涉及, 但是每个 JVM 实现都有 Safepoint;
  2. 什么时候需要安全点 Safepoint?

    1. GC 某些阶段的时候;
    2. JVM TI 捕获 stacktrace 的时候;
    3. 类重新定义的时候(Class redefinition), 比如 BCI 代码 Instrument 的时候;
    4. 捕获 heap dump 的时候;
    5. 锁膨胀的时候 (monitor deflation);
    6. 锁从偏向锁取消的时候(Lock unbiasing);
    7. 方法逆优化的时候(Method deoptimization);
    8. 其它...
  3. 对于 Zing JVM 实现, 分为全局安全点( global Safepoint) 和 线程安全点 (Thread Safepoint), 对于 Hotspot (Oracle/OpenJDK)系列只有全局安全点;
  4. 所有的 JVM 实现都在某些地方需要全局安全点( global Safepoint);

参考:

http://psy-lob-saw.blogspot.com/2016/02/why-most-sampling-java-profilers-are.html
http://psy-lob-saw.blogspot.com/2015/12/safepoints.html
https://psy-lob-saw.blogspot.com/2014/03/where-is-my-safepoint.html

google search: with-gc-solved-what-else-makes-jvm-pause

标签: none

添加新评论