GC Roots的确定(枚举根结点)
可达性分析的GC Roots的节点主要在全局性的引用(例如常量或类静态属性即静态变量)与执行上下文(栈帧中的本地变量表)中,但是,方法去往往数百兆,逐个检查里面的引用太过消耗时间。
另一个原因是GC(垃圾收集)停顿的问题,因为枚举根结点时必须停顿所有的Java执行线程(Stop The World),否则对象引用如果不断变动,那么结果将没有意义。
解决方案是在停顿时使用一组称为OopMap的数据结构代替一个不漏的检查完所有执行上下文和全局的引用位置,在类加载完成的时候,HotSpot会把对象内什么位置上是什么类型的数据计算出来,在JIT编译过程中也会在特定位置记录下栈和寄存器中哪些位置是引用。
安全点
在OopMap的帮助下,HotSpot可以快速准确的完成GC Roots枚举,但是有一个问题:可能导致引用关系变化,或者说OopMap内容变化的指令非常多,如果为每一条指令都生成对应的OopMap,将会需要大量的额外空间。
实际上,只是在特定的位置记录生成OopMap记录,这些位置称为安全点,即程序执行时并非在所有的地方都能停顿下来开始GC,只有到达安全点才能暂停。
安全区域
安全区域是指在一段代码片段中,引用关系不会发生变化。这个区域的任何地方开始GC都是安全的。可以看作是扩展了的安全点。
当线程执行到Safe Region中的代码时,首先标识自己已经进入了Safe Region,那样,在当这段时间里JVM要发起GC时,就不用管标识自己为Safe Region状态的线程了。当线程要离开Safe Region时,要检查系统是否已经完成了根结点枚举(或是整个GC过程),如果完成了,线程就继续执行,否则就要等待知道收到可以安全离开Safe Region的信号为止。