G1垃圾回收

G1垃圾回收.png

G1

调优场景

Evacuation Failure

"evacuation failure", "to-space exhausted", "to-space overflow", "promotion failure"之类的字眼。这些术语的概念在G1 GC是相似的

巨型对象和巨型对象分配

对于 G1 GC,任何超过区域一半大小的对象都被视为“巨型对象”。此类对象直接被分配到老年代中的“巨型区域”。这些巨型区域是一个连续的区域集。StartsHumongous 标记该连续集的开始,ContinuesHumongous 标记它的延续。

在分配任何巨型区域之前,会检查标记阈值,如有必要,还会启动一个并发周期。

在清理阶段或完整的垃圾回收周期内,标记周期结束时会清理死亡的巨型对象。

为了减少复制开销,巨型对象未包括在疏散暂停中。完整的垃圾回收周期会对巨型对象进行压缩。

由于每个 StartsHumongous 和 ContinuesHumongous 区域集只包含一个巨型对象,所以没有使用巨型对象的终点与上个区域的终点之间的空间(即巨型对象所跨的空间)。如果对象只是略大于堆区域大小的倍数,则此类未使用的空间可能会导致堆碎片化。

如果巨型分配导致连续的并发周期,并且此类分配导致老年代碎片化,请增加 -XX:G1HeapRegionSize,这样一来,之前的巨型对象就不再是巨型对象了,而是采用常规的分配路径。

当未找到能放下巨型对象的连续分区时,G1会首先尝试扩展堆空间,扩展失败时,启动串行gull gc。

引用处理

-XX:PrintReferenceGC在GC日志中输出各种引用详细GC数据。

通常,在G1年轻代或者混合收集中,当PrintGCDetails输出中的Ref Proc时间超过GC暂停时间总数的10%时,需要进行调优:

1.-XX:+ParalleRefProcEnabled激活多线程引用处理,负面影响是会抢占用户线程时间片。

2.第一点作用不明显时,观察GC日志,找到导致Ref Proc处理时间过长的引用类型,优化应用程序减少对该类型引用的使用。

软引用特别说明:

由于软引用对象只会在OOM前回收,所以软引用对象可能会长期占用内存而频繁触发老年代收集周期,使用-XX:SoftRefLRUPolicyMSPerMB可以控制软引用对象回收时机,

回收周期

年轻代GC

对象从eden区分配失败时触发,copy eden + from survivor -> to survivor,超过晋升阈值的对象copy到老年代。

  • -XX:MaxGCPauseMillis 200ms

    JVM会根据该参数调整年轻代大小。如果用户设置了-Xmn或者-XX:NewRatio等年轻代空间调整参数,会导致暂停目前参数失效。

  • -XX:G1NewSizePercent 5%

  • -XX:G1MaxNewSizePercent 60%

  • -XX:MaxTenuringThreshold 15

混合GC

触发时机:

当老年代分区占用总堆比例超过阈值(默认45%)时,触发混合GC。

初始标记:和下一次年轻代GC一起,STW并行标记,收集所有的GC Roots。

并发标记:多线程并发协同标示存活对象图。

重新标记:STW并行重新标记上个阶段产生的新垃圾。

并行回收:垃圾清理。

  • -XX:ConGCThreads

    设置并行标记的线程数。默认值为并行垃圾回收线程数 (ParallelGCThreads) 的 1/4 。

增大该值将会占用应用线程处理时间,降低吞吐量,因为并发GC线程和应用线程同时工作。

  • 初始标记

    借道年轻代的STW执行,标记出GC Roots直接可达的对象,将NTAMS置到分区顶部。

- -XX:InitiatingHeapOccupancyPercent IHOP 45%

  老年代占用比例超过该值时触发并发标记周期。
  • 根分区扫描

    年轻代存活对象作为“根分区”,扫描“根分区”对老年代的引用。

  • 并发标记周期

    使用基于写前栅栏的SATB快照标记算法(应用线程将发生更改前的引用放入stab_queue,由并发标记线程定期处理,以此找到标记开始时刻的存活对象快照),在多个并发标记周期不断交换PTAMS和NTAMS完成标记。

https://www.jianshu.com/p/9e70097807ba

  • 重新标记

    STW,GC线程并行处理所有生效的SATB缓冲区及所有更新(Rset更新?)。处理引用。

  • 清除

    识别所有空闲分区,清理空闲分区RSet,释放到空闲队列;

    整理堆分区,为混合垃圾回收识别出高效率的老年代分区;

    RSet梳理(比如,标记过程发现RSet中记录的某个对象已经死亡,将该记录从RSet中删除)。

高效率的分区:

1.存活对象少。

2.对象被别的分区对象引用数量少。这里数量多会导致RSet中PRT粒度粗化,增大RSet扫描开销。

交换位图、指针?并发标记周期也交换?

  • 混合回收

    • -XX:G1MixedGCLiveThresholdPercent 85%

      old generation region 中的存活对象的占比,低于该值时才会被选入 CSet。

    • -XX:G1MixedGCCountTarget 8

      设置标记周期完成后,对存活数据上限为 G1MixedGCLIveThresholdPercent 的旧区域执行混合垃圾回收的目标次数。默认值是 8 次混合垃圾回收。混合回收的目标是要控制在此目标次数以内。

  每次混合收集老年代CSet的最小数量 = 混合收集周期将回收的候选老年代分区总数/G1MixedGCCountTarge

  

  

- -XX:G1HeapWastePercent 10%

  混合收集周期中发现垃圾占总堆比例低于该值时,停止混合收集周期

- -XX:G1OldCSetRegionThresholdPercent 10%

  每次混合收集暂停收集分区上限,默认总堆的10%

Full GC

触发时机:对象分配失败时?

使用串行垃圾收集器对整个堆全面压缩。

G1的设计目标通过不断调优而不再需要full GC。

公共

  • -XX:G1HeapRegionSize

    超过该值50%的对象将被视为巨型对象,直接分配在老年代。JDK 8u40之前,巨型对象由混合GC并发收集周期的清除阶段回收,之后可以在年轻代GC回收。

1MB~32MB,G1默认将堆划为为约2048个Region。

  • -XX:G1ReservePercent=10

    设置作为空闲空间的预留内存百分比,以降低目标空间溢出的风险。默认值是 10%。增加或减少百分比时,请确保对总的 Java 堆调整相同的量。

copy对象到to-space时产生对象晋升,老年代空间不足时会扩展老年代堆空间,老年代空间已达上限会产生晋升失败,增大预留内存占比可避免晋升失败。

  • -XX:ParallelGCThreads

    设置 STW 工作线程数的值。将 n 的值设置为逻辑处理器的数量。n 的值与逻辑处理器的数量相同,最多为 8。

如果逻辑处理器不止八个,则将 n 的值设置为逻辑处理器数的 5/8 左右。这适用于大多数情况,除非是较大的 SPARC 系统,其中 n 的值可以是逻辑处理器数的 5/16 左右。

堆空间调整

JVM通过在Xms和Xmx之间动态调整堆大小及年轻代大小,以满足用户设置的GC暂停时间MaxGCPauseMillis和GCTimeRatio(用户线程时间/GC线程时间)的目标。

RSet

引用关系

PRT 粒度?

关系维护

维护时机:

对象引用关系变化时(包括引用赋值、GC移动对象等),触发写栅栏代码,维护Rset。

若发生一个跨区引用关系变化,G1垃圾收集器会将相应的card加入到“脏卡片队列”。“并发优化线程”会扫描队列中的卡片来更新RSet。当“并发优化线程”来不及处理不过来时,会挂起用户线程,让用户线程也加入到更新Rset。

全局卡片表

在任意收集周期,扫描Rset与PRT时,会将扫描到的引用记录标记到全局卡片表,避免重复扫描。在收集周期的最后将该表清空,显示为Clear CT。

工作窃取机制

收集活动图

活动流程

关键算法

https://www.jianshu.com/p/548c67aa1bc0

RSET

  • 写后栅栏

    https://www.jianshu.com/p/870abddaba41

    • 并发优化线程
  • 写前栅栏

    • SATB

      https://www.jianshu.com/p/9e70097807ba

年轻代收集

如何确保新生代对象被老年代引用的时候不被gc?(查询老年代对象来确认对新生代对象的引用避免误回收)

机制:当老年代存活对象多时,每次minor gc查询老年代所有对象影响gc效率(因为gc stop-the-world),所以在老年代有一个write barrier(写屏障)来管理的card table(卡表),card table存放了所有老年代对象对新生代对象的引用。

所以每次minor gc通过查询card table来避免查询整个老年代,以此来提高gc性能。

初始标记

并发标记周期

混合收集周期

GC日志

跑出完成GC日志,标记日志说明。

https://www.jianshu.com/p/ac1ba3479c08

引用

堆外内存回收

https://www.jianshu.com/p/35cf0f348275

Reference&ReferenceQueue

https://www.jianshu.com/p/f0da6c1af815

finalize

https://www.jianshu.com/p/9d2788fffd5f

你可能感兴趣的:(G1垃圾回收)