对象存活判定算法和垃圾收集算法
3.4.1 枚举根节点
使用一组称为OopMap的数据解构来完成枚举根节点;
枚举根节点即为GC Roots的一个枚举;
GC Roots中节点++一般++为全局性引用(常量、类静态属性) 和 栈帧中的本地变量表。
具体的GC Roots(了解)
- 虚拟机栈(栈桢中的 局部变量表中的 本地变量表)中的引用的对象
- 方法区中的 类的静态属性 引用的对象
- 方法区中的常量引用的对象
- 本地方法栈中JNI(Native方法)的引用的对象
枚举根节点的2个问题
-
- 如果逐一检查引用,则肯定消耗性能,所以不可能这么做
-
- 可达性分析中,不能出现分析对象过程中对象引用关系还在不断变化,这是导致GC停顿(Stop The World)的重要原因,枚举根节点是必须停顿的;
解决方法:使用OopMap数据解构
- 类加载完成后,会把对象内什么偏移量上是什么类型的数据计算出来,在JIT编译过程中,在特定的位置(即安全点)使用OopMap记录下栈和寄存器哪些位置是引用,这样GC在扫描时就可以直接得知这些信息了。
3.4.2 安全点
在OopMap的协助下,HotSpot可以快速且准确地完成GC Roots枚举
安全点Safe Point:是指一些特定的位置,当线程运行到这些位置时,线程的一些状态可以被确定,比如记录OopMap的状态,从而确定GC Root的信息,使JVM可以安全的进行一些操作,比如开始GC。
如果每条指令都生成OopMap那将需要大量的额外空间。此时在特定的位置上 (即安全点)使程序不是在所有的地方都停顿(Stop The World)下来开始GC,只有在到达安全点时才停顿开始GC。
安全点的选取:
- 安全点的选定:不能使GC等待时间过长也不能使GC频繁触发,如具有方法调用、循环跳转、异常跳转的指令才会有安全点。
从线程角度看,safepoint可以理解成是在代码执行过程中的一些特殊位置,当线程执行到这些位置的时候,说明虚拟机当前的状态是安全的,如果有需要,可以在这个位置暂停
如何让GC发生的时候让所有线程都跑到”安全点“停下来。方式有两种:
- 抢先中断式(弃用):当发生GC时让所有线程都停下来,如果有线程没有到安全点,就让该线程继续跑到安全点
- 主动式抢断:当线程执行GC需要中断时,不需要对线程进行操作,而是设置一个标志位,各线程主动去轮询这个标志位。标志位和安全点在同一个位置,发现标志位为真是就将自己这个线程中断挂起
3.4.3 安全区域
安全区域是指一段代码段中引用关系不会发生变化,在该区域何时何地开始GC都是安全的。线程执行安全区域的代码块时会标识自己已经进入了安全区域,此时如果JVM发起GC线程不会再标志中断状态标识,线程离开安全区域时会检查GC枚举GC Roots根节点(或者是整个GC过程)是否已经完成,如果完成了就继续执行,没完成的话就等待GC完成回收任务收到可以离开的信号再离开安全区域。