HotSpot算法实现

枚举根节点

以可达性分析中从GC Roots节点找引用链为例,节点主要是全局的引用(常量或静态属性),与执行上下文(如栈帧中的本地变量表),现在很多应用仅方法区就有数百兆,当检查这里面的引用时,必然消耗很多的时间。另外,在进行这项分析时,整个执行系统要冻结在某个时间节点上,不可以出现分析过程中,对象的应用关系还在不断变化的情况,如果不满足的话分析的准确性就无法得到保证。这点是导致GC进行时必须要停顿所有执行线程的一个重要原因(这件事被称为Stop The World)。

由于目前主流Java虚拟机使用的都是标准式GC,所以当系统停顿下来以后并不需要一个不漏的得检查完所有执行上下文和全局引用的位置,在HotSpot的实现中,使用一组称为OopMap的数据结构来达到这个目的,在类加载完成的时候,HotSpot就把对象内什么偏移量上是什么类型的数据计算出来,在JIT编译过程中,也会在特定的位置 (安全点) 记录下栈和寄存器中哪些位置是引用的,这样GC在扫描的时候就直接得到这些信息了。

安全点

在OopMap的协助下,HotSpot可以快速且精准的完成GC Roots枚举,但会导致问题出现:可能导致引用关系变化,或者说OopMap内容变化的指令很多,如果每一条指令都生成对应的OopMap,会需要大量的额外空间,这样的GC成本会很高。

实际上,HotSpot只是在特定的位置记录了这些信息,也就是安全点(Safe Point),程序只有在到达安全点之后才能暂停,进行GC ,安全点的选择不能太少,以至于让GC等待时间过长,也不能过于频繁,导致过分增大运行时的负荷,所以,安全点的选定是基于“是否具有让程序长时间执行的特征”为标准的----长时间执行最明显的特征就是指令序列复用,例如方法调用,循环跳转,异常跳转等。

对于安全点,需要考虑的问题是如何让所有的线程都到最近的安全点在停顿下来,方法有两个:抢先式中断和主动式中断。抢先式中断不需要线程的执行代码的配合,在GC发生时,首先把线程全部中断,如果有线程中断的地方不在安全点上,就恢复此线程,让他跑到安全点上;主动式中断是当GC需要中断线程的时候,不直接对线程操作仅仅简单的设置一个标志,各个线程执行时主动去轮循这个标志,发现中断标志为真时就自己中断挂起,轮询标志的地点和安全区是重合的,另外再加上创建对象需要分配内存的地方

安全区域

当程序不执行时也就是没有分配CPU时间 ,无法响应JVM的中断请求,典型的就是线程是Sleep和Blocked状态时,需要用到安全区域来解决。

安全区域(Safe Region)是指在一段代码片段中,引用关系不会发生变化,在这个区域中的任意地方开始GC都是安全的,也可以把它看做是扩展的安全点

当线程执行到安全区中的代码时,首先标识自己已经进入到了安全区,那样当在这段时间里JVM要发起GC时,就不用管标识自己为安全区状态的线程了,当线程要离开安全区时,他要检查系统是否已经完成了根节点枚举(或是整个GC过程),如果完成了,那线程继续执行,否则就必须等待知道收到可以安全离开安全区域的信号位置.

 

猜你喜欢

转载自blog.csdn.net/weixin_43844810/article/details/85999817