SafePoint
听说SafePoint这个词很久了,但是一直没有花时间去搞懂它。知道JVM 的GC活动会导致Stop the world, 原因是线程会停在SafePoint上。虽然知道GC是STW的主要原因,但一直有以下几个疑问:
SafePoint存在的原因是什么,解决什么问题,即Why SafePoint
SafePoint到底是什么?What is SafePoint.
什么时候会进到SafePoint? When SafePoint.
如何诊断SafePoint 引发的问题?How to identify SafePoint problems.
什么是SafePoint?
SafePoint是Java代码中的一个线程可能暂停执行的位置。SafePoint保存了在其他位置没有的一些运行时信息。SafePoint保存了线程上下文中的任何东西,包括对象,指向对象或非对象的内部指针。(原文如下:)
A safepoint is a place in Java code where a Java thread may halt its execution. The safepoint contains information for the runtime that isn’t available in other places, such as which registers contain objects (needed by the GC). The safepoint also guarantees that everything in the thread context is either an object, an internal pointer to an object or not an object.
在JVM处于SafePoint时,所有在执行代码的Java线程将会被暂停。不与JVM交互的运行Native Code的能继续执行(如果需要通过JNI访问Java 对象,调用JAVA方法,从Native回到JAVA的话,则必须等到Safepoint结束。
SafePoint的发起者可以做一些疯狂的事情:比如对java object的排他性访问,移除堆上的对象,改变正在执行方法的代码(比如栈上替换).排他性访问就是Why SafePoint的原因,不至于这个过程中有Race condition的问题。
何时进入SafePoint
从线程状态的角度看,Waiting/Idle/Blocked/Running native code是处于SafePoint的,Running Java code是处在非SafePoint的状态。处于Safepoint时,Heap不能访问,Java代码不能执行。当全部Java线程都处于SafePoint状态时,JVM处于全局SafePoint,可用于执行:GC, 优化,Stack trace dump,锁偏向,类重定义等。我们的以下行为会导致进入SafePoint: 新生代耗尽,大对象分配导致的老年代耗尽,进入同步块等。
SafePoint是如何工作的呢?
在JVM中,SafePoint协议是协同的。每个线程通过检查SafePoint数据结构的状态来确定是否需要暂停自己来进入安全态。
对于编译的代码,JIT通过在代码中适当的位置插入SafePoint检查的代码(通常在调用的返回和循环的退出)
对于解释的代码,JVM保存了两张字节码的执行表,如果需要进行SafePoint检查,JVM会在两张表之间切换。(实现待研究)
SafePoint的实现使用的非常巧妙地办法,通常的内存变量的检查需要大量的内存屏障(Memery barrier,不知道的自己Google之,百度之,懒人请猛点https://www.kernel.org/doc/Documentation/memory-barriers.txt ),使用mprotected强制JAVA的写操作按顺序执行。 至于在线程在不同的状态下,是如何进入safePoint的,有兴趣的可以看看源码:http://hg.openjdk.java.net/jdk7u/jdk7u/hotspot/file/tip/src/share/vm/runtime/safepoint.cpp 里面的注释也写得非常清楚。
SafePoint对性能有何影响
方法的内联可导致SafePoint的移除,SafePoint也可能因为以下因素被延时:大循环,大的内存拷贝(System.arrayCopy/Unsafe.copyMemory),线程中断,Page Fault。从非safePoint到SafePoint的时间长,可能意味着更长的SWT时间,如果需要GC,有可能因为某个线程一直没有到达SafePoint而导致GC线程无法工作。
如何查看JVM SafePoint行为
使用JVM 参数:
1 | -XX:+PrintSafepointStatistics |
Stop The World的四个阶段
根据1
2-XX:+PrintSafepointStatistics
–XX:PrintSafepointStatisticsCount=1
参数虚拟机打印的日志文件可以看出,safepoint的执行一共可以分为四个阶段:
Spin阶段,因为jvm在决定进入全局safepoint的时候,有的线程在安全点上,而有的线程不在安全点上,这个阶段是等待未在安全点上的用户线程进入安全点。
Block阶段,即使进入safepoint,用户线程这时候仍然是running状态,保证用户不在继续执行,需要将用户线程阻塞。
Cleanup阶段,这个阶段是JVM做的一些内部的清理工作。
VM Operation阶段,JVM执行的一些全局性工作,例如GC,代码反优化。
只要分析这个四个阶段,就能知道什么原因导致的STW时间过长。
其他资料
(这篇bog详细说明了如何将用户线程阻塞)[http://blog.csdn.net/iter_zc/article/details/41892567]