JVM-G1垃圾收集器

6 篇文章 1 订阅

包含内容

  • G1 回收原理,优势
  • G1后为什么有ZGC

G1

简述

  • 出现背景
    在发生Minor GC时,由于Survivor区已经放不下去,多出对象只能通过代际提升(generation promtion)到老年代。
    但是,糟糕的是,老年代因为空间碎片的缘故,会发生concurrent mode failure而无法满足及时响应,影响用户体验.此时会老年代就会降级为Serial old垃圾收集器进行收集。
    Serial old垃圾收集器收集的后果比发生concurrent model failure更严重,因为其有major GC发展成 Full GC造成更长停顿,且时间未知
    
  • 问题图示
    CMS面临问题

G1解决方法

  • 定义一个停顿时间,然后反向推断收集内容。如领导年初制定Key Performance Indicator.然后将GC任务分解成一个个小任务,每次清理一些垃圾,保证其不会造成过长停顿,最后将垃圾收集完毕
    G1要求在任意1s内,停顿不得超过10ms,即给给他制定KPI。G1会近年来达成这个目标。它能够推算出本次要收集的大体区域,已增量方式完成收集

  • 设置G1参数,制定1s内GC停顿时间 -XX:MaxGCPauseMillis=10

G1 垃圾收集器

  • 目标替换CMS,一款软实时垃圾回收器。参数较CMS的72个,减少至26个
  • 全程Garbage First GC.为达到上述KPI,其在堆的划分与CMS等垃圾收集器不同。
    其他的垃圾收集器,都是对某个年代的整体收集(minor gc对年轻代,major GC对老年代,Full GC是所有堆)
    G1 将堆划分为很大方,每一份当做一个小目标,部分上目标易达成
    G1在逻辑上仍有有年轻代,年老代划分
    
  • G1 逻辑上的年轻代,年老代划分
    1.G1也有Eden区和Survivor区概念,只是内存上不再连续,有一小份一小份组成。
    2.一小份区域大小固定,大小一致(1M~32M间的2的幂指数),叫作Region-小堆区。可以是Eden区,Survivor区,old区。
    3.如果对象过大,一个Region无法放置,上图中有个很大黄色区域,叫Humongous Region,大小超过Region 50%对象,会分配在此。
    4.Region大小设置参数: -XX:G1HeapRegionSize=<N>M
    
  • G1 代际空间划分
    G1 代际空间划分
  • 回收策略,优先回收垃圾最多的Region

G1回收过程

代际回收

````
逻辑上G1分年轻代和年老代,但其比例不固定。为了达到-XX:MaxGCPauseMillis规定效果,G1会自动调整二者比例。
如果强行指定-Xmn或-XX:NewRation去设定年轻代和年老代比例,G1设置的-XX:MaxGCPauseMillis会失效。
````

G1回收流程

  • (1)G1”年轻代回收”,同样叫Minor GC,如前和CMS类似,发生时机是Eden区满时。
  • (2)老年代垃圾收集,严格说不是收集,是一个”并发标记”过程,顺便清理一点点对象。
  • (3)真正清理发生在”混合模式”,它不止清理年轻代,还会将老年代一部分区域清理。
  • GC日志中,(1)过程叫[GC pause(G1 Evacuation Pause) (young)],(2)过程是[GC pause(G1 Evacuation Pause) (mixed) ],Evacuation 是转移的意思,和copy意思类似。
  • (1),(2),(3)三者模式间隔不固定,如1次minor gc后,发生2次并发标记,接着发生7次 mixed gc
  • 三者模式图示

Remembered Set

  • 简称Rset,一个空间换时间的数据结构
  • 同CMS中的卡表(Card Table)类似,解决跨代引用的问题,记录和维护Region之间的对象引用关系
  • 和Card Table不同,Rset是记录了其他Region中对象对本Region的对象引用,属于point-into(谁引用了我Region内的对象)。而Card Table是point-out(我引用了谁的对象,老年代的对象引用了哪个年轻代的对象,卡表对应的老年代对象卡页会标记dirty)。Rset有点倒排索引的意味
  • 可以将Rset理解成Hash,可以是引用的本Region对象的地址,value是对应的卡页集合(其他Region对象引用该Region对象的集合)
  • RSet记录关系图示
    RSet记录关系图示
  • Rset 避免对整个堆区所有Region进行扫描,是的部分手机成为可能
  • 年轻代Region的Rset只保存老年代的引用(对应的卡页),这是因为年轻代回收时针对所以年轻代Region,没必要年轻代对象记录其他年轻代对象,故年轻代Rset有可能为空(无老年代引用他)。
  • 年老代Region的Rset只保存年老代对象对它的引用。因为老年代回收前会先对年轻代进行回收。这是Eden变空了,而回收过程中会扫描Survivor分区,所以没必要保存年轻代的引用
  • Rset通常占用较大空间,5%或者更高,计算开销也较大。
  • 为维护Rset,程序运行时,写入某个字段就会产生一个post-write barrier。为了减少该开销,将内容放入Rset过程是异步,经过诸多优化:Write Barrier把脏卡信息放到本地缓冲区,使用专门GC线程收集脏卡信息,并将其传给被引用Region的Rset
  • 参数-XX:G1ConcRefinementThreads或-XX:ParallelGCThreads可以控制这个异步过程。如果并发优化线程更不是缓冲区速度,就会在用户进程完成。

G1 具体回收过程

  • G1还有一个CSet概念,全称collection set,即收集集合,保存一次GC中执行垃圾回收的Region.GC是在Cset中所有存活数据(live data)都会被转移

年轻代回收

  • 年轻代是一个STW过程,它的跨代引用通过RSet记录来追溯,会一次性回收掉所有Region。

  • JVM启动时,G1会先准备好Eden区,程序在运行过程不断在Eden创建对象,当所有Eden区都满,G1启动一次年轻代回收过程(STW)

  • 年轻代收集包括下面回收阶段

    1.扫描根: 根可看做前面介绍的GCRoots,加上RSet记录的其他Region的外部引用
    2.更新RSet: 同CMS处理dirty card queue中的卡页类似,更新RSet。此阶段完成后,RSet可以准确的反映老年代对所在的内存分段中对象的引用
    3.处理RSet: 识别被老年代对象指向的Eden中对象,这些被指向的Eden中对象被认为是存活对象
    4.复制对象: 收集算法依然是Copy算法,对象复制进行内存回收。此阶段对象树被遍历,Eden区内存段中存活对象会被复制到Survivor区的空的Region,过程和其他垃圾回收算法一样,包括对象年龄和晋升。
    5.处理引用: 处理Soft,Weak,Phantom,Final,JNI Weak等引用。结束收集
    
  • 年轻代收集流程
    年轻代收集流程

  • 年轻代对象在内存中回收流程
    年轻代对象在内存中回收流程

并发标记

  • 当整个队使用达到一定比例(默认为45%%),并发标记阶段就会被启动。这个比例可以通过-XX:InitiatingHeapOccupancyPercent进行配置
  • Concrrent Marking为Mixed GC提供标记服务,并不是一次GC过程的一个必须环节。这个过程与CMS的并发可取消预清理相似,是非必须。具体流程如下
    1.初始标记(initial Mark) 
    共用了Minor GC的暂停,这是因为他们可以复用root scan。也是STW的,但是标记与GC Roots直接关联的对象。时间较短
    2.Root 区扫描(Root Region Scan)
    3.并发标记
    该阶段从GC Roots开始对heap中对象标记,标记线程与应用线程并发执行,并且手机各个Region存活对象信息
    4.重新标记(Remarking)
    和CMS相似,也是STW。标记那些在并发标记阶段发生变化的对象。
    5.清理阶段(Cleanup)
    该过程不需要STW.如果发现Region里面全是垃圾,在这个阶段立马被清除。不全是垃圾的Region,并不会马上被处理,会在Mixed GC阶段,进行清理。
    
  • G1的并发标记如何应对新的对象变化
    由算法SATB保证。STAB全称是Snapshot At The Beginning ,它作用是保证在并发标记阶段的正确性
    快照是逻辑上的,主要有介个指针,将Region分成多个区域。如图,并发标记期间分配的对象会在Next TAMS和top之间。
    ![SATB算法标记并发情况下新对象发生变化](https://img-blog.csdnimg.cn/20200306202037957.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2R5bWtrag==,size_16,color_FFFFFF,t_70)
    

混合回收(Mixed GC)

  • 内并发清理年老代中整个整个的小堆区是一种最优情形。混合收集不知清理年轻代,还会将一部分区域也加入到CSet中。
  • 通过Concurrent Marking阶段,我们统计年老代垃圾占比。在Minor GC之后,若该占比超过-XX:G1HeapWastePercent(默认堆大小的5%)参数设置的阈值,下次就会触发Mixed GC。因为这种情况下,GC耗时较大,内存回收有限。所以此参数可以调整Mixed GC的频率。
  • 还有参数G1MixedGCCountTarget,用于控制一次并发标记后,最多执行Mixed GC次数。

ZGC

G1的trade-off

  • 归功于G1预测模型和抽新的小堆(Region)分区模式。线上严重GC问题有效减少
  • 但是如果定下严苛KPI和预测模型失效,或应用内存非常吃紧,内存进行一部分一部分的回收根本不够,始终要进行整个heap的回收。那么G1要做的工作量一点也不比其他垃圾收集器少,而且本身算法复杂,效率要比其他垃圾收集器更差

ZGC

  • ZGC优势
1.停顿时间同G1,不超过10ms
2.避免像G1停顿时间不会随着堆的增大,始终维持在10ms下。
3.可支持几百MB ,甚至几T堆大小(最大4T)
4.完全没有年轻代和年老代,只分为一块块page,每次进行GC,都会对page进行压缩操作,所以无碎片问题。
5.ZGC能感知NUMA架构,提供内存访问速度
6.与传统收集算法相比,ZGC直接在对象引用指针做文章,用来标记对象状态,所以只能在64位机器上。
7.只能在Linux使用,使用优势明显,等待普及
  • ZGC收集算法策略

小结

  • 着重查看数据结构RSet
  • 相对CMS,G1有了更可靠,更容易驾驭度。配置参数大幅减少26个。而且有RSet,SATB等算法支持,Remark阶段效率更高。
  • G1最重要概念是Region。它采用分而治之,部分收集。对年代用minor GC。堆达到一定阈值-XX:G1HeapWastePercent时,使用Mixed GC。尽力达到设定的停顿目标
  • G1 垃圾回收分三种,其中部分标记,为更加复杂的Mixed GC阶段做了充足准备
  • JVM G1垃圾收集器参数样例
    JAVA_OPTS=”$JAVA_OPTS -XX:NewRatio=2(新生代占比) 
    -XX:G1HeapRegionSize=8m -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m  -XX:MaxTenuringThreshold=10(新生代年龄提升值老年代阈值)  
    -XX:+UseG1GC
            -XX:InitiatingHeapOccupancyPercent=45 -XX:MaxGCPauseMillis=200  
            -version:gc
    -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintReferenceGC
    -XX:GCLogFileSize=32m -Xloggc:./var/run/gc.log.$(date +%Y%m%d%H%M)
    -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./var/run/heap-dump.hprof
    -Dfile.encoding=UTF-8 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sum.management.jmxremote.authenticate=false”
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值