JVM之枚举GC Roots 根节点,安全点,安全区域。

引言 

  判断对象是否被回收的算法引用计数算法可达性分析算法

引用计数法:

可达性分析算法:是根据GC Roots根节点作为起始点向下搜索引用链,找不到引用链则判定对象可回收。

在这里插入图片描述

可作为GC Roots根节点的对象主要是在全局性的引用(如常量、类静态属性)和执行上下文中(如栈帧中的本地变量表),现在的很多应用仅方法区就有数百兆,逐个检查里边的引用显然很耗费时间。

另外,可达性分析必须在一个确保一致性的快照中进行——这里的“一致性”的意思是指,在整个分析期间整个执行系统看起来就像被冻结在某一个时间点上,不能出现分析过程中引用关系还在不断变化的情况。

通俗的说就是进行可达性分析的时候引用关系不能发生变化。这将导致GC进行时必须停顿所有的Java执行线程。(在GC ROOTS 根节点枚举都必须暂停用户的所有线程这就是我们通常所说的stop-the-word,即使不停顿的CMS垃圾收集器,根节点枚举时也是会发生停顿。)

就是我们接下来要说的解决方案。

正文:

GC ROOTS 根节点枚举:

HotSpot中采用OOPMap来避免在数百兆的方法区里逐个检查里面的引用,避免了垃圾回收时影响效率,将GC ROOTs 根节点集合对象维护在OOPMap的数据结构中(解决快速定位GC ROOTS 对象集合问题),

首先在类加载完成的时候,HotSpot就把对象内什么偏移量上是什么类型的数据计算出来,在JIT编译过程中,也会在特定的位置记录下栈和寄存器中哪些位置是引用。这样,GC在扫描的时候,就可以根据OOPMap上记录的信息准确定位到哪个区域中有对象的引用,这样大大减少了通过逐个遍历来找出对象引用的时间消耗。

已经解决了快速定位GC ROOTS 对象集合问题,那还有一个问题,就是如何保证GC ROOTS 根节点枚举的时候,引用关系不会发生变化。解决方案-------》安全点

安全点:

导致OOPMap 发生变化的指令集非常多,如果为每条指令都生成一个OOPMap,那将需要大量的额外存储空间,显然不科学,HotSpots 也没有这么做,只是在特定位置来记录OOPMAP信息。这些特定的位置就是安全点。

即程序执行时并非在所有地方都能停顿下来开始GC,只有在到达安全点时才能暂停。Safepoint的选定既不能太少以致于让GC等待时间太长,也不能过于频繁以致于过分增大运行时的负荷。所以,”安全点“的选择基本上是以程序”是否具有让程序长时间执行的特征“为标准来选定的。因为每条执行指令执行的时间都非常地短暂,程序不太可能因为指令流长度太长这个原因而过长时间运行,而程序”长时间的运行“实际上就是指令序列的一个复用。例如方法调用、循环跳转、异常跳转等,所以具有这些功能的指令才会产生”安全点“。而当我们选取好”安全点“之后,我们又是怎样使所有执行线程跑到”安全点“时停顿下来呢?

 ② ”安全点“的两种中断方式(抢先式中断和主动式中断)

     “抢先式中断”不需要线程的执行代码去主动配合,在GC发生时,首次会把所有的线程全部中断,如果发现有些线程中断点不是安全点,就恢复该线程直到安全点上停止。”主动式中断“实际上就是线程主动轮询的一个过程,当GC需要中断线程时,不直接对线程进行操作,仅仅简单的设置一个标志,这个轮询标志当然要与安全点相重合。各个线程在执行的时候都会主动去询问这个轮询标志:”我是否到了该中断的点了?“。现在大部分虚拟机都采用是”主动式中断”方式,因为它相对“抢先式中断”方式避免了一个中断——>启动——>又中断的一个过程。

     设置“安全点”虽然保证了大部分线程停顿,但总有一些线程比较“懒”。例如,当GC请求中断时,该线程正在偷懒sleep(),JVM不可能等该线程睡醒之后到达安全点之后才能进行可达性分析过程,而此时如果该线程睡醒了恰巧GC又在进行可达性分析或者是回收,那该线程又该何去何从呢?所以JVM又在安全点的基础上加了一个双重保险——安全区域。

   ③ “安全点”的双重保证——安全区域

     安全区域是指在一段代码片中,引用关系不会发生改变,实际上就是一个安全点的拓展。当线程执行到安全区域时,首先标识自己已进入安全区域,那样,当在这段时间里JVM要发起GC时,就不用管标识自己为“安全区域”状态的线程了,该线程只能乖乖的等待根节点枚举或者整个GC过程完成之后才能继续执行

====================如有错误请指正,谢谢============================

如何更好的理解gc请看此图。

网友提问JVM-GC回收机制?今天就彻底讲解一下GC回收机制到底咋用

猜你喜欢

转载自blog.csdn.net/Hao_JunJie/article/details/110232653