HotSpot虚拟机上垃圾收集算法实现

本文深入探讨HotSpot虚拟机的垃圾回收机制,介绍枚举根节点、安全点及安全区域的概念,阐述如何在保证一致性的前提下进行高效垃圾回收。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在HotSpot虚拟机上实现这些算法时,必须对算法的执行效率有严格的考量,才能保证虚拟机高效运行。

一、枚举根节点(Stop the World停顿,准确式GC,OOPMap)

      1、从可达性分析算法中从GC Roots节点找引用链这个操作为例,可作为GC Roots的节点主要在【全局性引用(例如常量或类静态属性)】与【执行上下文(例如栈帧中的局部变量表)】中

      2、现在很多应用仅仅方法区就有数百兆,如果要逐个检查这里面的引用,必然会消耗很多时间。

      3、可达性分析对执行时间的敏感还体现在【GC停顿】上,因为这项分析工作必须在一个能确保【一致性】的【快照】中进行。

             这里的"一致性"的意思是指:
               在整个【分析期间】整个【执行系统】看起来就像被冻结在某个时间点上,
               不可以出现分析过程中【对象引用】关系还在不断变化的情况,
               该点不满足的话【分析结果】【准确性】就无法得到保证

               这点是导致【GC】进行时必须【停顿】所有【Java执行线程】("Stop The World")的其中一个重要原因

               即使是在号称(几乎)不会发生停顿的CMS收集器中,【枚举根节点】时也是必须要【停顿】的 

        4、现在主流的Java虚拟机使用【准确式GC】, 所以当执行系统停顿下来后,并不需要一个不漏的检查完所有【执行上下文】和【全局引用】的位置

               虚拟机应当是有办法直接知道哪些地方存放着【对象引用

                  在HotSpot的实现中,使用一组称为【oopMap】的数据结构来达到这个目的

                 在【类加载】完成时候,HotSpot就把【对象】内什么【偏移量】上是什么【类型的数据】计算出来

                在【JIT编译】过程中,也会在特定的位置记录下【栈】和【寄存器】中哪些位置是【引用】

                这样,【GC】在扫描时就可以直接得知这些信息了

二、安全点(只有到达安全点才可以停顿,开始GC)

     1、在【OopMap】的协助下,【HotSpot】可以【快速】且【准确】的完成【GC Roots枚举】

     2、实际上,HotSpot没有为【每条指令】都生成【OopMap】,只是在"特定的位置"记录了这些信息,这些位置称为【安全点】(Safe Point)

            即【程序执行】时并非在所有地方都能停顿下来开始GC,只有在到达【安全点】时才能【暂停

     3、Safe Point的选择定即不能太少以致于让【GC】等待时间太长
           也不能过于频繁以致于过分增大运行时的负荷

     4、所以,【安全点】的选定基本上是以程序"是否具有让程序长时间执行的特征"为标准进行选定的

            因为每条指令执行的时间都非常短暂,程序不太可能因为指令流长度太长这个原因而过长时间运行

            "长时间执行"的最明显特征就是【指令序列复用】,例如:方法调用、循环跳转、异常跳转等。

           所以,具有这些功能的【指令】才会产生安全点(Safe Point)

     5、对于Safe Point,还有一个问题是:
           如何在【GC】发生时让【所有线程(这里不包括执行JNI调用的线程)】都"跑"到最近的【安全点】上再停顿下来。

           1、抢先式中断

                   不需要【线程】的执行代码主动去配合,在GC发生时,首先把【所有线程】【全部中断】

                   如果发现有线程中断的地方不在【安全点】上,就恢复线程,让它"跑"到【安全点】上

                   现在几乎没有虚拟机实现采用抢先式中断来【暂停线程】从而响应GC事件。

           2、主动式中断

                  【主动式中断】思想是:
                   当GC需要中断线程的时候,不直接对线程操作,仅仅简单地设置一个标志,各个线程执行时主动去轮询这个标志,发现中断标志为真时就自己                       中断挂起。

                  【轮询标志】的地方和安全点是重合的,另外再加上创建对象需要分配内存的地方。

三、安全区域

          1、使用【SafePoint】似乎已经完美解决了【如何进入GC】的问题,但实际情况却不一定

                 【SafePoint】机制保证了程序执行时,在不太长的时间内就会遇到可进入GC的SafePoint。

          2、但是,程序"不执行"的时候,所谓的【程序不执行】就是【没有分配CPU时间】,典型的例子就是:
                 线程处于Sleep状态或Blocked状态,这时候线程无法响应JVM的中断请求,"走"到安全的地方去中断挂起,JVM显然不太可能等待线程重新被分                    配CPU时间。

          3、对于这种情况,就需要【安全区域(Safe Region)】来解决

                 【安全区域】是指:
                  在一段代码片段之中,【引用关系】不会发生变化。
                  在这个区域中的任意地方开始GC都是安全的。

                 我们也可以把【Safe Region】看做是被扩展了的【Safe Point】

          4、线程执行到【Safe Region】中的代码时,首先【标识】自己已经进入了【Safe Region】,
                当在这段时间里JVM要发起GC时,就不用管标识自己为【Safe Region】状态的线程了。  

         5、线程要离开【Safe Region】时,它要检查系统是否已经完成了【根节点枚举】(或是整个GC过程)

               如果完成了,那线程就继续执行

              否则它就必须等待直到收到可以安全离开【Safe Region】的信号为止。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值