枚举根节点、安全点、安全区域

1. 枚举根节点

可作为GC Roots的节点主要在全局性引用(常量、类静态属性)和执行上下文(栈帧中的本地变量表)。

枚举过程要保证一致性快照和枚举效率:

2. 安全点(Safepoint)

Hotspot没有为每条指令生成OopMap,只是在特定的位置记录了这些信息,这些位置成为安全点。

程序执行时并不是在每个地方都能停顿下来执行GC,再有在到达安全点之后才能暂停。

安全点的选定既不能太少以至于让GC等待时间太长,也不能过于频繁以至于过分增大运行的负荷。所以,安全点的选定是以程序“是否具有让程序长时间执行的特征”为标准进行选定的。“长时间执行”最明显的特征就是指令序列复用,例如方法调用、循环跳转、异常跳转等,多以具有这些功能的指令才会产生Safepoint。

有两种方案:抢先式中断和主动式中断。

抢先式中断是在GC发生时,首先把所有的线程中断,如果发现有线程不是在安全点中断,则恢复线程,让它跑到安全点上。现在几乎没有虚拟机采用抢先式中断来暂停线程。

主动式中断是当GC需要中断线程的时候,不直接对线程操作,仅仅设置一个标志,各个线程执行时主动去轮询这个标志,发现中断标志为真时就自己中断挂起。

3. 安全区域(Safe Region)

Safepoint保证了程序执行时在不太长的时间内就会遇到可进入GC的Safepoint,但是程序不执行的时候(没有分配CPU空间,例如线程处于sleep或blocked状态)线程无法相应JVM的中断请求,这种情况需要安全区域来解决。

安全区域是指在一段代码片段中,引用关系不会发生变化。在这个区域中任意地方开始GC都是安全的。可以把SafepointRegion看作是Safepoint的扩展。在线程执行遇到Safe Region时,首先标示自己已经进入Safe Region,这样,在这段时间JVM要发起GC时,就不用管标示为Safe Region状态的线程了。在线程要离开Safe Region时,要先检查系统是否已完成根节点枚举或GC过程,如果完成了线程就继续执行,否则它就必须等到收到可以安全离开Safe Region的信号为止。