JVM 系列之: 再谈 java 中的 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 比如容易出现在循环遍历的情况,还是使用我们之前做 null 测试用的例子:
运行结果如下:
标红的就是传说中的 safepoint。
线程什么时候会进入 safepoint
那么线程什么时候会进入 safepoint 呢?
一般来说,如果线程在竞争锁被阻塞,IO 被阻塞,或者在等待获得监视器锁状态时,线程就处于 safepoint 状态。
如果线程再执行 JNI 代码的哪一个时刻,java 线程也处于 safepoint 状态。因为 java 线程在执行本地代码之前,需要保存堆栈的状态,让后再移交给 native 方法。
如果 java 的字节码正在执行,那么我们不能判断该线程是不是在 safepint 上。
safepoint 是怎么工作的
如果你使用的是 hotspot JVM,那么这个 safepoint 是一个全局的 safepoint,也就是说执行 Safepoint 需要暂停所有的线程。
如果你使用的是 Zing,那么可以在线程级别使用 safepoint。
我们可以看到生成的汇编语言中 safepoint 其实是一个 test 命令。
test 指向的是一个特殊的内存页面地址,当 JVM 需要所有的线程都执行到 safepint 的时候,就会对该页面做一个标记。从而通知所有的线程。
我们再用一张图来详细说明:
thread1 在收到设置 safepoint 之前是一直执行的,在收到信号之后还会执行一段时间,然后到达 Safepint 暂停执行。
thread2 先执行了一段时间,然后因为 CPU 被抢夺,空闲了一段时间,在这段时间里面,thread2 收到了设置 safepoint 的信号,然后 thread2 获得执行权力,接着继续执行,最后到达 safepoint。
thread3 是一个 native 方法,将会一直执行,知道 safepoint 结束。
thread4 也是一个 native 方法,它和 thread3 的区别就在于,thread4 在 safepoint 开始和结束之间结束了,需要将控制器转交给普通的 java 线程,因为这个时候 JVM 在执行 Safepoint 的操作,所以任然需要暂停执行。
在 HotSpot VM 中,你可以在汇编语言中看到 safepoint 的两种形式:'{poll}’ 或者 ‘{poll return}’ 。
总结
本文详细的讲解了 JVM 中 Safepoint 的作用,希望大家能够喜欢。
本文作者:flydean 程序那些事
本文链接:http://www.flydean.com/jvm-safepoint2/
本文来源:flydean 的博客
欢迎关注我的公众号:程序那些事,更多精彩等着您!
版权声明: 本文为 InfoQ 作者【程序那些事】的原创文章。
原文链接:【http://xie.infoq.cn/article/3ae899c9d19ecfcac6fac715d】。文章转载请联系作者。
评论 (2 条评论)