垃圾回收器 G1

Garbage First垃圾回收器 G1        jdk9取代了CMS垃圾回收器

        在jdk中进程    2009 JDK 6u14体验
                2012 JDK 7u4 官方支持
                2017 JDK 9   默认

        适用场景
            同时注重吞吐量和低延迟,默认的暂停目标是200ms
            超大堆内存,会将堆划分为多个大小相等的Region
            整体上是标记+整理算法,两个区域之间是复制算法

        相关参数    
            -XX:+UseG1GC            开关
            -XX:G1HeapRegionSize=size    G1堆中的Region大小
    -        -XX:MaxGCPauseMills=time    


    
    阶段
        young Collection:            新生代垃圾回收
    
        Young Collection+Concurrent Mark:    新生代垃圾回收+并发标记
        
        Mixed Collection:            混合收集

    
        先新生代垃圾收集
        当老年代内存超过阈值时,下一次新生代垃圾回收会开启并发标记,并进行混合收集,
            对新生代,老年代区域垃圾回收


        工作流程
        young Collection:        会STW,停止其他用户线程

            先伊甸园垃圾回收,伊甸园满了后会进行新生代垃圾回收,复制幸存对象到幸存区to
            交换幸存区from和幸存区to位置,当幸存区内快存满了,再次垃圾回收
            一定时间后,一些年龄达到的就晋升老年代
            
            新生代垃圾回收的跨代引用
                新生代垃圾回收是找根对象,可达性分析,找存活对象,复制算法到幸存区

                但是,找新生代对象的根对象时,根对象一部分会在老年代中,
                如果直接遍历老年代对象是效率很低
        
                将老年代划分为无数个card,每个card空间512k,
                如果card中有对象引用新生代对象,会对这个card标记为脏card
                新生代对象空间会记录引用它的脏card地址,减少标记GCRoot的时间
        
                然后minorgc时,新生代清理复制算法,引用变更的时候,
                    通过post-writer barrier + dirty carf queue队列
                    用线程concurrentRefinementThreads更新RememberedSet

        Young Collection + Concurrent Mark:    
            新生代垃圾收集时对根对象GCRoot初始标记
            老年代占用堆空间比例达到阈值时,进行并发标记(不会停止用户线程STW)
            阈值:    -XX:InitiatingHeapOccupancyPercent=percent)(默认45%)
            
            拷贝存活            会STW暂停用户线程
                会对伊甸园,幸存区,老年代都进行一个全面的垃圾回收
                新生代:    伊甸园区进行复制算法到幸存区,到年龄就晋升老年代
                老年代:    采用复制算法将幸存对象复制到老年代另一个区域
                    G1垃圾回收器会根据最大暂停时间有选择的回收
                    (只对可能垃圾较多的区域回收,减少暂停时间达到目标)

        
        Mixed Collection:
                进行最终标记(防止并发下的引用改变)    会STW暂停用户线程
                拷贝存活    (如上)            会STW


    重新标记remake
        在G1和CMS中都有应用,就是在并发标记后都要重新标记
            因为如果在标记的同时,用户线程将一个对象的引用取消了,该对象被标记清除,
            而此时,该对象又被用户线程引用了,就会出错
        当对象引用发生改变时,就会将其加入一个写屏障,(就是将对象加入队列中,并标记为未处理)
        并在重写标记阶段将对象从队列中取出,重新检查,如果是被引用就不清理

    G1的jdk8后的一些优化:
        jdk8u20    :    字符串去重
            将所有新分配的字符放入一个队列,当新生代回收时,G1并发检查是否有字符串重复
            如果值一样,就引用同一个char[]
            在jvm内部,使用了不同的字符串表
                和String.intern()不同,String.intern关注的是字符串对象
                而字符串去重关注的是char[],
                在jvm内部,使用了不同字符串表

            优点:    节约内存
            缺点:    略微占用cpu,新生代回收时间增加


        jdk8u40:    并发标记类卸载
            所有对象都经过并发标记后,就能指定哪些类不再被使用,
            当类加载器所有类不再使用,就卸载所有类
            -XX:+ClassUnloadingWithConcurrentMark

        jdk8u60:    巨型对象回收
            一个对象占region一半时,叫巨型对象
            G1不会对巨型对象进行拷贝
            回收时被优先考虑
            G1跟踪老年代所有的incoming引用,
                老年代incoming引用为0的巨型对象可以在新生代垃圾回收时被处理


        jdk9:        并发标记起始时间调整
            并发标记在堆空间占满前完成,否则退化为FullGC
            jdk9前,要使用-XX:InitiatingOccupancyPercent(默认45%)
            jdk9可以动态调整
                -XX:InitiatingHeapOccupancyPercent 设置初始值
                进行数据采样并动态调整
                添加一个安全的空档空间

                    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值