首先从垃圾回收说起,当发生GC时,需要从方法区本地变量表等地方获取GC Roots,但如果是单纯的遍历查找的话是非常亏的,GC发生时本身就停止了所有的线程,不能让这一操作耗费太多的时间。

HotSpot为优化GC Roots的查找,采用了OopMap这一数据结构,一旦类加载动作完成的时候,HotSpot就会把对象内什么偏移量上是什么类型的数据计算出来,在即时编译过程中,也会在特定的位置记录下栈里和寄存器里哪些位置是引用。

通过OopMap,JVM可以快速枚举出GC Roots,但是对象引用随时都在变,如何维护OopMap又是一个问题。HotSpot的做法就是设置Safepoint。在一个方法中往往有一个或多个安全点,这些安全点把一个方法分割成了多个段,每一段都有一个OopMap,仅当线程执行到达安全点时,才能执行GC。

多线程下,发生GC时,每一个线程在到达安全点时都会挂起(这个功能通过线程的轮询实现)。当所有线程都被挂起后,才能执行GC操作。

当线程无法响应虚拟机的中断请求时,比如Sleep或者Blocked状态,线程不能走到安全点挂起自己,虚拟机也不可能等他被重新激活,所以又引入了一个Safe Region安全区域来解决。当一段代码中,引用关系不会发生变化时(比如从线程Sleep到被激活的这段时间),称这段代码为安全区域,处在安全区域的线程在发生GC时会继续执行,如果执行到安全区域末尾时,GC仍未结束,则会挂起并等待GC结束。如果GC已经结束,则会当作无事发生接着执行下面的代码。