GCRoot与safePoint


HotSpot虚拟机使用可达性分析算法确定对象是否可以被GC。

可达性分析算法从一系列GCRoot对象开始,向下搜索引用链,如果一个对象没有与任何GCRoot对象关联,这个对象就会被判定为可回收对象。

GCRoot包括以下对象:

  1. 虚拟机栈上的本地变量表引用的对象
  2. 方法区中类的静态属性引用的对象
  3. 方法区中常量引用的对象
  4. 本地方法栈中JNI引用的对象

这一过程称为根节点枚举,也就是垃圾回收中的标记过程,当前所有的垃圾收集器,在标记阶段都必须停止所有java执行线程(stop the world),以保证对象引用状态不会发生变化。

HotSpot虚拟机作为准确式虚拟机,维护了一个专门的映射表(OopMap)记录哪些位置存放着对象引用,来快速完成根节点枚举过程。

为每一个操作记录OopMap不现实,HotSpot虚拟机引入了safePoint。

safePoint是程序中的某些位置,线程执行到这些位置时,线程中的某些状态是确定的,在safePoint可以记录OopMap信息,线程在safePoint停顿,虚拟机进行GC。

线程停顿方式有两种,抢先式中断和主动式中断:

  1. 抢先式中断:虚拟机需要GC时,中断所有线程,让没有到达safePoint的线程继续执行至saftPoint并中断
  2. 主动式中断:虚拟机不直接中断线程,而是在内存中设置标志位,线程检查到标志位被设置,运行至saftPoint时主动中断

safePoint一般出现在以下位置:

  1. 循环体的结尾
  2. 方法返回前
  3. 调用方法的call之后
  4. 抛出异常的位置

这些位置保证线程不会长时间运行而无法到达safePoint,避免其他线程都停顿等待本线程。

safePoint无法解决线程未达到safePoint并处于休眠或等待状态的情况,此时引入safeRegion的概念。

safeRegion是代码中的一块区域或线程的状态,在safeRegion中,线程执行与否不会影响对象引用的状态。线程进入safeRegion会给自己加标记,告诉虚拟机可以进行GC;线程准备离开safeRegion前会询问虚拟机GC是否完成。

推荐阅读更多精彩内容