G1 GC基本逻辑


1  MixedGC基本过程
在G1GC中,有两种主要的垃圾回收过程:Young GC和Mixed GC。这两者都是为了回收堆内存中的垃圾对象,但是他们关注的区域和工作方式有所不同。

Young GC:

Young GC主要负责回收Young Generation(包括Eden区和Survivor区)。大多数新创建的对象都首先在Eden区分配,在一段时间后,如果这些对象仍然存活,它们将被移动到Survivor区或Old区。Young GC通常会频繁发生,因为大多数对象的生命周期都很短,很快就会变成垃圾可以被回收。

Mixed GC:

与Young GC不同,Mixed GC不仅回收Young Generation,还会回收部分Old Generation。Mixed GC发生的条件是在并发标记周期结束后,也就是说,它会在完成全堆的并发标记之后进行。在Mixed GC中,G1GC会选择一些可以回收的老年代区域进行清理,这样可以在不进行Full GC的情况下,尽可能地清理掉一些长时间存活的垃圾对象

在G1GC中,实际上只有YoungGC. 或者说MixedGc是跟随YoungGC
1 Mixed GC触发条件:

1)如果堆内存的使用率超过了一个阈值(默认是45%,可以通过-XX:InitiatingHeapOccupancyPercent参数进行调整),那么将会启动一个并发周期,而Mixed GC则在并发周期结束后开始。
2)老年代的区域已经满了。G1GC会尽可能地避免Full GC,所以当老年代的区域已经满了,并且并发标记已经完成,G1GC会触发Mixed GC以回收老年代的部分区域
   老年代的使用率达到 -XX:G1OldCSetRegionThresholdPercent 参数设置的阈值,G1 GC 将会尽管不满足 G1HeapWastePercent 的要求,也会强制执行 Mixed GC,以防止老年代填满导致 Full GC


MixedGC阶段:
1)初始标记阶段
这个过程需要进入Stop the World的,仅仅只是标记一下GC Roots直接能引用的对象,这个过程速度是很快的。如下图,先停止系统程序的运行,然后对各个线程栈内存中的局部变量代表的GC Roots,以及方法区中的类静态变量代表的GC Roots,进行扫描,标记出来他们直接引用的那些对象
 
2)并发标记阶段
这个阶段会允许系统程序的运行,同时进行GC Roots追踪,从GC Roots开始追踪所有的存活对象,并对这个过程对象的变化做记录,比如哪些对象失去了引用,哪些对象是新建的。如下图所示。(这个阶段也是很耗时的,要追踪全部存活的对象,但跟系统并发运行,影响不大)

3)最终标记阶段
这个阶段会进入Stop the World,系统程序是禁止运行的,但是会根据并发标记阶段记录的那些对象修改,最终标记一下有哪些存活对象,有哪些是垃圾对象。

4)混合回收阶段

   计算存活对象数量:在并发标记阶段,垃圾收集器会遍历对象图并标记存活对象。这个过程可以帮助G1GC了解每个区域的存活对象数量。
   计算回收收益:根据每个区域的存活对象数量,G1GC会计算回收收益,即回收某个区域可以释放多少空间。
   选择回收集合:在计算完回收收益后,G1GC会根据预设的暂停时间目标(例如通过-XX:MaxGCPauseMillis参数设置)来选择哪些区域应该被包含在回收集合中。这个过程中,G1GC会优先选择回收收益较高的区域。

   这个阶段G1允许多次执行混合回收,也就是说先停止系统工作,执行回收,恢复系统运行,再停止系统运行,再回收,再恢复…这么一个流程。每次回收的间隔是由G1自己控制的,回收执行次数可以通过参数-XX:G1MixedGCCountTarget来设置,这个参数默认回收次数是8次,同时有一个参数-XX:G1HeapWastePercent,默认值是整个堆大小5%,就是说当前回收集合内即将空出来的区域大于整个堆的5%,就会立即停止混合回收了。正常默认回收次数是8次,但是可能到了4次,发现空闲Region大于整个堆的5%,就不会再进行后续回收了。
   G1HeapWastePercent参数(默认5%),控制了回收集合内总的region的内存大小,
         设置太大,
              则经过可能最多8次后还是达不到条件这个阈值。这可能会导致垃圾回收的暂停时间变长,对应用程序的响应时间产生影响。
              同时,如果 G1 GC 将这种回收效益不高的 region 也加入到回收集合(CSet)中,虽然能回收一些垃圾,但大部分空间仍然被活动对象占据,该 region 的空间利用率并未显著提高。
                   而实际上这些 region 的可回收空间并不多,这就造成了空间的浪费。也导致额外的 CPU 时间被用于回收这些 region
              如果内存使用效率较低,可能间接导致内存使用率较快达到 IHOP 阈值  InitiatingHeapOccupancyPercent,从而导致频繁触发并发标记。
         设置太小,
               导致mixed gc 很快就结束。进而导致很多需要回收的region得不到回收,也会影响内存里利用率。能使堆内存使用率更容易达到 -XX:InitiatingHeapOccupancyPercent(IHOP)阈值,从而触发更频繁的并发标记。
                如果堆空间使用率持续上升,可能会触发 Full GC,从而导致更长的垃圾收集暂停时间。
                
                
   如果发现老年代中可回收的对象不足以满足预设的暂停时间目标(由 -XX:MaxGCPauseMillis 参数设置):
   G1 GC 可能会提前结束 Mixed GC 状态,避免不必要的工作,因为继续执行 Mixed GC 可能无法释放足够的空间,却会消耗更多的 CPU 时间。
   
        a)通常是指老年代中可以被回收并释放的对象数量不足,也就是说,老年代中的大部分对象都还被程序所使用,无法被回收。
        b)也可能是短寿命的对象,这些对象在年轻代就被回收了,而长寿命的对象(通常会被分配到老年代)相对较少。 

  当老年代中可回收的对象超过预设的暂停时间,G1 GC 会提前结束 Mixed GC,避免回收时间过长,以尽量满足预设的暂停时间目标。
  但是,如果经常发生, 这可能导致老年代中未回收的对象增加,从而降低堆内存的使用效率。
  如果经常出现这种情况,可能需要调整 G1 GC 的配置参数或优化应用代码以减少老年代中的可回收对象。例如,可以增加-XX:G1OldCSetRegionThresholdPercent和-XX:G1HeapWastePercent的值,以允许 G1 GC 在 Mixed GC 阶段回收更多的老年代 Region,或者优化应用代码以减少长寿命对象的生成。
 

对于已经被加入到 Collection Set (CSet) 中的 region,无论它们是年轻代的还是老年代的,G1 GC 都会在当前的 GC 周期中进行回收。    如果没有可回收对象,则直接转YoungGC.


2     G1GC 新生代是动态的:
-XX:G1NewSizePercent和-XX:G1MaxNewSizePercent,分别为新生代比例的设定数值的下限和上限,默认值分别为5%和60%。G1会根据实际的GC情况(主要是暂停时间)来动态的调整新生代的大小,主要是调整Eden Region的个数。

以下是 G1 GC 动态调整新生代大小的几个重要因素:

暂停时间目标:G1 GC 通过 -XX:MaxGCPauseMillis 参数设置暂停时间目标。为了尽量满足这个目标,G1 GC 可以根据前几次垃圾收集的数据,动态地调整新生代的大小,以影响下一次垃圾收集的暂停时间。

应用程序行为:G1 GC 会根据应用程序的行为,如对象分配速率和对象存活率,动态地调整新生代的大小。对于分配密集型的应用,G1 GC 可能会增大新生代的大小以容纳更多的对象。对于对象存活率高的应用,G1 GC 可能会减小新生代的大小以避免存活对象过多导致的复制成本。

并发标记:G1 GC 会尽量在并发标记阶段结束后立即触发一次 Mixed GC。为了保证并发标记能够在合适的时间结束,G1 GC 会根据堆内存使用率和历史数据,动态地调整新生代的大小。

因此,新生代的动态性是 G1 GC 实现可预测的停顿时间和高吞吐量目标的一个重要方式。

你可能感兴趣的:(jvm,java)