SafePoint是什么
safepoint是什么
java程序里面有很多很多的java线程,每个java线程又有自己的stack,并且共享了heap。这些线程一直运行呀运行,不断对stack和heap进行操作。
这个时候如果JVM需要对stack和heap做一些操作该怎么办呢?
比如JVM要进行GC操作,或者要做heap dump等等,这时候如果线程都在对stack或者heap进行修改,那么将不是一个稳定的状态。GC直接在这种情况下操作stack或者heap,会导致线程的异常。
怎么处理呢?
这个时候safepoint就出场了。
safepoint就是一个安全点,所有的线程执行到安全点的时候就会去检查是否需要执行safepoint操作,如果需要执行,那么所有的线程都将会等待,直到所有的线程进入safepoint。
然后JVM执行相应的操作之后,所有的线程再恢复执行。
线程什么时候会进入safepoint
那么线程什么时候会进入safepoint呢?
一般来说,如果线程在竞争锁被阻塞,IO被阻塞,或者在等待获得监视器锁状态时,线程就处于safepoint状态。
如果线程再执行JNI代码的哪一个时刻,java线程也处于safepoint状态。因为java线程在执行本地代码之前,需要保存堆栈的状态,让后再移交给native方法。
如果java的字节码正在执行,那么我们不能判断该线程是不是在safepint上。
safepoint主要特定位置
1. 循环的末尾 (防止大循环的时候一直不进入safepoint,而其他线程在等待它进入safepoint)
2. 方法返回前
3. 调用方法的call之后
4. 抛出异常的位置
之所以选择这些位置作为safepoint的插入点,主要的考虑是“避免程序长时间运行而不进入safepoint”,比如GC的时候必须要等到Java线程都进入到safepoint的时候VMThread才能开始执行GC,如果程序长时间运行而没有进入safepoint,那么GC也无法开始,JVM可能进入到Freezen假死状态。在stackoverflow上有人提到过一个问题,由于BigInteger的pow执行时JVM没有插入safepoint,导致大量运算时线程一直无法进入safepoint,而GC线程也在等待这个Java线程进入safepoint才能开始GC,结果JVM就Freezen了。
safepoint只能处理正在运行的线程,它们可以主动运行到safepoint。而一些Sleep或者被blocked的线程不能主动运行到safepoint。这些线程也需要在GC的时候被标记检查,JVM引入了safe region的概念。safe region是指一块区域,这块区域中的引用都不会被修改,比如线程被阻塞了,那么它的线程堆栈中的引用是不会被修改的,JVM可以安全地进行标记。线程进入到safe region的时候先标识自己进入了safe region,等它被唤醒准备离开safe region的时候,先检查能否离开,如果GC已经完成,那么可以离开,否则就在safe region呆在。这可以理解,因为如果GC还没完成,那么这些在safe region中的线程也是被stop the world所影响的线程的一部分,如果让他们可以正常执行了,可能会影响标记的结果
可以设置JVM参数 -XX:+PrintSafepointStatistics –XX:PrintSafepointStatisticsCount=1 来输出safepoint的统计信息
转载:https://blog.csdn.net/z69183787/article/details/81103214