写在前面
本文隶属于专栏《100个问题搞定Java虚拟机》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!
本专栏目录结构和文献引用请见100个问题搞定Java虚拟机
解答
安全点
在 Java 虚拟机里,传统的垃圾回收算法为了枚举 GC Roots,必须要经历一个Stop-the-world(STW)的过程,即停止其他非垃圾回收线程的工作,直到完成垃圾回收。
Java 虚拟机中的 STW 是通过安全点(safepoint)机制来实现的。
当 Java 虚拟机收到 STW 请求,它便会等待所有的线程都到达安全点,才允许请求 STW 的线程进行独占的工作。
程序执行时并非在所有地方都能停顿下来开始GC,只有在到达安全点时才能暂停。
当然,安全点的初始目的并不是让其他线程停下,而是找到一个稳定的执行状态。
在这个执行状态下,Java 虚拟机的堆栈不会发生变化。这么一来,垃圾收集器便能够“安全”地执行可达性分析。
安全区域
安全点机制保证了程序执行时,在不太长的时间内就会遇到可进入GC的安全点。
但是,当线程处于Sleep状态或者Blocked状态时,这时候线程无法响应JVM的中断请求,“走”到安全的地方去中断挂起,JVM也显然不太可能等待线程重新被分配CPU时间以响应请求。
对于这种情况,就需要安全区域(Safe Region)来解决。
安全区域是指在一段代码片段之中,引用关系不会发生变化。 在这个区域中的任意地方开始GC都是安全的、我们也可以把安全区域看做是被扩展了的安全点。
在线程执行到安全区域中的代码时,首先标识自己已经进人了安全区域,这样,当在这段时间里JVM要发起GC时,就不用管标识自己为安全区域状态的线程了。
在线程要离开安全区域时,它要检査系统是否已经完成了根节点枚举(或者是整个GC过程),如果完成了,那线程就继续执行,否则它就必须等待直到收到可以安全离开安全区域的信号为止。