HotSpot虚拟机使用可达性分析算法确定对象是否可以被GC。
可达性分析算法从一系列GCRoot对象开始,向下搜索引用链,如果一个对象没有与任何GCRoot对象关联,这个对象就会被判定为可回收对象。
GCRoot包括以下对象:
- 虚拟机栈上的本地变量表引用的对象
- 方法区中类的静态属性引用的对象
- 方法区中常量引用的对象
- 本地方法栈中JNI引用的对象
这一过程称为根节点枚举,也就是垃圾回收中的标记过程,当前所有的垃圾收集器,在标记阶段都必须停止所有java执行线程(stop the world),以保证对象引用状态不会发生变化。
HotSpot虚拟机作为准确式虚拟机,维护了一个专门的映射表(OopMap)记录哪些位置存放着对象引用,来快速完成根节点枚举过程。
为每一个操作记录OopMap不现实,HotSpot虚拟机引入了safePoint。
safePoint是程序中的某些位置,线程执行到这些位置时,线程中的某些状态是确定的,在safePoint可以记录OopMap信息,线程在safePoint停顿,虚拟机进行GC。
线程停顿方式有两种,抢先式中断和主动式中断:
- 抢先式中断:虚拟机需要GC时,中断所有线程,让没有到达safePoint的线程继续执行至saftPoint并中断
- 主动式中断:虚拟机不直接中断线程,而是在内存中设置标志位,线程检查到标志位被设置,运行至saftPoint时主动中断
safePoint一般出现在以下位置:
- 循环体的结尾
- 方法返回前
- 调用方法的call之后
- 抛出异常的位置
这些位置保证线程不会长时间运行而无法到达safePoint,避免其他线程都停顿等待本线程。
safePoint无法解决线程未达到safePoint并处于休眠或等待状态的情况,此时引入safeRegion的概念。
safeRegion是代码中的一块区域或线程的状态,在safeRegion中,线程执行与否不会影响对象引用的状态。线程进入safeRegion会给自己加标记,告诉虚拟机可以进行GC;线程准备离开safeRegion前会询问虚拟机GC是否完成。