一、什么是Stop the world
以可达性分析中从GC Roots节点找引用链为例,为了保证分析工作的过程中确保一致性——指整个分析期间整个执行系统看起来就像别冻结在某个时间点上,不可以出现分析过程中对象引用关系还在不断变化的情况。即使是在号称(几乎)不会发生停顿的CMS收集器中,枚举根节点时也是必须要停顿的。
这就导致GC进行时必须停顿所有Java执行线程,Sun将件事情称“Stop The World”
目前的主流Java虚拟机使用的都是准确式GC,所以当执行系统停顿下来后,不需要检查完所有执行上下文和全局的引用位置。在HotSpot的实现中,是使用一组称为OopMap的数据结构来达到得知哪些地方存放着对象的目的,在类加载完成时,HotSpot就把对象内什么偏移量上是什么类型的数据计算出来,在JIT编译过程中,也会在特定的位置记录下栈和寄存器中哪些位置是引用。
二、安全点
2.1什么是安全点
OopMap内容变化的指令非常多,如果为每一条指令都生成对应的OopMap,那将会需要大量的额外空间,这样GC的空间成本会很高。
因此HotSpot并没有为每条指令都声称OopMap,只是在特定位置记录了这些信息,这些位置称为安全点(Safepoint),即程序执行时并非在所有地方都可以停顿下来GC,只有在到达安全点是才能暂停。
安全点的选定既不能太多,让GC等待时间过长,也不能太多以至于过分增大运行时的负荷。安全点的选定基本上是以程序“是否具有让程序长时间执行的特征”为标准选定,“长时间执行”的明显特征就是指令序列复用,例如方法调用,循环跳转、异常跳转等,所以具有这些功能的指令才会产生SafePoint。
2.2如何到达安全点
这里有两种让程序到达最近安全点的方案:
- 抢先式中断(Preemptive Suspension):不需要线程上的执行代码主动去配合,在GC发生是,首先把所有线程都中断,如果发现有不在安全点的线程,就恢复它,让它到达安全点
- 主动式中断(Voluntary Suspension):不直接对线程操作,仅设置一个标志,各个线程主动去轮询这个标志,发现为true时就自己中断挂起,轮询标志的地点和安全点是重合的,另外再加上创建对象需要分配内存的地方。
二、安全区域
安全区(Safe Rangion)是指在一段代码片段之中,引用关系不会发生变化。在这个区域中的任意地阿芳开始GC都是安全的。我们也可以把安全区域看成扩展的安全点。
在线程执行到安全区域时,首先将自己标识进入了安全区域,这样,当这段时间内JVM要发起GC时,就不用管标识了Safe Ragion的线程了。当线程离开安全区域时,要检查是否完成了根节点枚举或整个GC,如果完成了就继续执行,否则必须等到可安全离开的信号为止。
安全区域应用于Sleep或Blocked状态的 线程,这时线程无法响应JVM中断请求,既无法到达安全点,也不太可能的呢古代重新被分配CPU。这种情况就需要安全区域来解决。