JAVA中的垃圾回收器(2)------G1

news2024/12/26 1:01:08

一)G1垃圾回收器:-XX:+UseG1GC:使用G1收集器

1)垃圾收集器迭代停顿时间越少越好,但是垃圾回收的总时间会增多,默认暂停时间默认是200ms,G1的内部底层算法非常复杂比CMS复杂,如果大内存,G1还比较有效果,但是如果堆内存不大,G1性能还不如CMS,在小内存效率依然不高;

2)注重于停顿时间和回收regin的效益比,适用于堆内存比较大的内存,最大停顿时间的优势就凸显出来了,停顿时间比较短,对于用户体验非常好,适用于高并发大内存的情况下,很好的解决大内存STW时间更长的问题;

3)空白的regin使用链表来进行连接

一)G1垃圾收集器介绍

1)G1垃圾回收器是一款面向服务器的垃圾收集器,主要针对的是配备多颗处理器以及大容量内存的机器,以极高的频率来满足GC停顿时间的要求的同时来尽量的提升吞吐量

2)虽然在物理上分代已经不连续了,但是在逻辑上还是存在着分代的概念的

G1在大内存中对整个用户的停顿时间可以控制的优势是非常明显的,如果内存特别大,那么可控停顿时间的优势就会非常明显

但是在小内存中G1的优势就不算是太明显了,因为G1内部有很多很难的内部算法细节,整个算法时间复杂度非常高,又要估计regin的回收价值,又要分配卡表和记忆集,本来CMS和parNew的垃圾回收也是可以的了;

3)G1堆将JAVA的堆划分成多个大小相等的独立区域,JVM最多有2048个regin,一般的regin大小等于堆内存大小除以2048,比如说堆的大小是4096M那么regin的大小就是2M,当然也是可以使用参数-XX:G1HeapReginSize来手动指定Regin的大小,但是推荐默认的计算方式

4)G1保留了年轻代和老年代的概念,但是不在是物理隔阂了,都是不连续的Regin的集合,默认年轻代对于堆内存的占比是5%,如果堆内存大小是4096M,那么年轻代大概占据200M的内存,大概是100个regin,可以使用-XX:G1NewSizePercent来设置新生代初始占比,在系统运行过程中JVM会不断给年轻代增加更多的regin,但是最多新生代的占比也没有超过60%,可以通过-XX:G1MaxNewSizePercent调整,年轻代中的Eden和Survivor对应的region也跟之前一样,默认8:1:1,假设年轻代现在有1000个region,eden区对应800个,s0对应100个,s1对应100个,一开始regin内存区域都是空的,随着空间不断被使用,年轻代不在扩容,程序运行后期这些不同的regin会被赋予不同的含义;

5)一个regin可能之前是年轻代,如果regin进行了垃圾回收,可能就变成了老年代,也就是说regin的功能区域可能会动态发生变化

6)G1垃圾收集器对于对象什么时候会转移到老年代和之前说过的原则一模一样,唯一不同的是针对于大对象的处理,G1有一个专门分配大对象的区域叫做Humongous区域,而不是让大对象直接进入到老年代的Regin中,在G1中有专门分配大对象的区域叫做Humongous区,大对象的判断规则就是一个对象超过了Regin区域的一半,按照上面的计算规则,每一个Regin的大小是2M,只要对象的大小超过了1M,就会被存放到Humongous,如果对象特别大,还有可能使用多个连续的Regin存放Humongous区专门存放短期巨型对象,不用直接进老年代,可以节约老年代的空间,避免因为老年代空间不够的GC开销FullGC的时候除了收集年轻代和老年代之外,也会将Humongous区一并回收;

1)G1垃圾收集器会让初始标记和最终标记和筛选回收的总的STW时间控制在一个设置的参数范围内,在筛选回收中G1垃圾回收器不一定会把所有的堆中的垃圾全部回收掉,可能在筛选回收之前并发标记过程中标记了很多非垃圾对象还有很多的垃圾对象要进行清理,但是在G1筛选回收阶段,因为要考虑到停顿时间,可能要把整个堆空间回收完成要400ms,但是程序员指定的STW时间是200ms,G1会有一个算法来预估回收多少块区域(预估每一块regin大概要回收多长时间)能够达到用户设置的最大停顿时间,剩余的区域下一次GC回收;

2)一共的GC总时间比CMS时间还长,ZGC的垃圾回收一次完整过程的时间可能会更久;

3)可不可以把GC的停顿时间指定的非常短呢,不要乱指定,既然需要停顿时间短一些,就指定为10ms,G1一次性清理的垃圾非常非常少,垃圾积累多了,可能会触发大级别的FullGC,直接STW,直接单线程垃圾收集,本来设置时间是200ms,但是你设置10ms,最终可能导致G1停顿时间失效;

4)G1垃圾回收器在后台维护了一个优先级列表,每一次根据允许的收集时间,优先进行选择回收加载最大的regin,比如说一个regin花费200ms能够回收10M垃圾,另外一个regin花费50ms能够回收20M垃圾,在总回收时间有限的情况下,G1当然会优先回收后面这个;

5)一块区域存活的对象越多,垃圾回收的效益比越低,又要移动对象更新引用啥的,应该优先回收垃圾比较多的regin区域;

二)G1垃圾回收分类: 
2.1)MinorGC:

伊甸园区默认占用整个堆空间的5%,假设现在伊甸园区放满了,之前的垃圾回收器Parallel NEW,伊甸园区满了之后会触发young GC,但是对于G1来说并不是这样,原始的伊甸园区放满以后并不会触发Young GC,G1有一个最大默认停顿时间默认值是200ms,G1垃圾回收器会进行计算,假设这5%的伊甸园区如果要是做young GC的回收接近200ms,会触发minorGC,但是如果垃圾回收器计算下来整个伊甸园区计算下来只需要50ms,远远小于200ms,那么就说明此时伊甸园区太小了,垃圾其实并不多,但是G1是分区算法5%的伊甸园区满了以后,G1垃圾回收器会把这些新new出来的对象放在其他新的空闲的空的regin格子中,那么此时这个regin的格子就是一个新的伊甸园区,此时如果隔一段时间之后发现系统评估的伊甸园区总的回收时间接近于200ms,此时就会触发youngGC,G1垃圾回收器在进行触发young GC之前会评估一下计算一下当下伊甸园区的回收时间是否接近于最大停顿时间,如果接近了,就做minor GC,如如果最大停顿时间远远大于伊甸园区的总的回收时间,那么此时伊甸园区会扩容,把这些新对象丢到新的空区域,这些新的空区域就又变成了伊甸园区,直到G1垃圾回收器判断整个伊甸园区的垃圾回收时间接近于最大停顿时间,此时才会触发minor GC;

2.2)MixedGC:

不是FullGC,老年代的堆空间的占有率达到参-XX:IniatiattingHeapingOccupanyPercent设定的值来触发,根据最大停顿时间来计算回收效益比,它会回收所有的Young和部分Old区域(根据GC的停顿时间确定Old区域垃圾收集的先后顺序)以及大对象区域正常情况下G1的垃圾收集是先做MixedGC,主要采用的是复制算法,需要把各个Regin中的存活的对象拷贝到别的Regin区域里面去,拷贝过程中如果发现没有空的Regin能够承载拷贝对象就会触发一次FullGC,会进行回收所有的新生代和部分老年代,因为它还是要根据停顿时间来进行计算最大回收效益比,对于大对象区域的HS也会回收,

2.3)FullGC:

如果说触发MixedGC的占用老年代的参数设置的比较小比如说45%,那么55%都是新生代,如果新生代太多,说明此时新生代占用regin过多,此时就没有额外的空闲regin供老年代对象来进行复制了,此时就会触发Full gc,因为复制算法是对剩余的空间要求是比较高的,如果剩余空间太小没有充足的空间进行复制,此时没空间存放来年代对象,要对停顿时间做一个好的把控,此时直接单线程收集,使用单线程垃圾回收器进行回收的,STW时间非常长;

之前的垃圾回收器,只是需要在年轻代记录一个卡表就可以了,但是在G1来说,每一个regin区域都有一个卡表,记录着老年代区域对于新生代的引用关系;

停止系统程序,然后采用单线程进行标记、清理和压缩整理,好空闲出来一批Region来供下一次MixedGC使用,这个过程是非常耗时的,Shenandoah优化成多线程收集了;

针对于-XX:MxGCPauseMillis这个参数来说,如果说这个值设置的特别大,可能会导致系统运行很久,年轻代可能都已经占用到了堆内存的60%了,才会触发YGC,那么此时存活的对象很多,此时就有可能导致幸存区存不下那么多的对象,就会进入到老年代,或者是说年轻代GC以后,存活下来的对象过大导致进入到幸存区触发了动态年龄判断机制,达到了幸存者区的50%,也会是得一些对象快速进入到了老年代

XX:MaxGCPauseMills这个参数的值,在保证他的年轻代gc别太频繁的同时,还得考虑每次gc过后的存活对象有多少,避免存活对象太多快速进入老年代,频繁触发mixedgc

1)CMS并发清理的过程中回收垃圾是和用户线程并发执行的,G1的筛选回收过程是会造成STW的;

2)CMS并发清理过程中会产生内存碎片,但是G1时使用的复制算法,不会产生内存碎片;

3)G1使用了Regin划分内存空间以及有优先级的区域回收方式,保证了G1在有限的垃圾回收时间内尽可能保证比较高的回收效率

三)G1的使用场景:

1)假设现在在每秒几十万数据量的高并发的系统的环境下,KFK一秒钟可以处理几十万单,肯定要使用到大内存,此时就是需要使用GC,小内存是肯定不符合要求的,假设一个订单一KB,几十万的消息,每一秒钟有5 6个G放到新生代,这个时候有大量数据对象直接晋升到老年代,等了几秒以后发现老年代也放不下,可能每几秒钟就需要做一次FullGC,但是触发fullGC可能,消息还没有执行完,此时还是放不出来空间,此时直接报OOM;

2)所以为了避免系统触发FullGC或者导致OOM,针对于这种高并发场景肯定是用大内存的机器,因为大部分高并发对象都是朝生夕死,经过一次minorGC有可能就被回收,所以将新生代的空间设置的比较大,5 6g都可以,但是此时minorGC的执行是非常慢的,会造成卡顿,这个时候做GCroot,遍历整个年轻代的对象速度很慢,尽管存活对象不多,但是要遍历几十个G的新生代还是比较浪费时间,所以young GC的回收速度不一定比老年代回收速度快,因为如果新生代特别大,就是一个反例,还有就是新生代的垃圾回收非常慢,如果不使用G1,那么此时的用户会非常卡顿,如果不使用G1那么STW时间非常长

3)如果用G1,使用固定停顿时间200ms,每一次GC也可以收集好几个G,可以回收内存空间,虽然整个GC时间比较多,但是不会导致用户等待时间非常长,虽然总的吞吐量还不错,对于用户体验还不错;

4)G1边处理业务,边收集垃圾,STW降到非常短的时间

为什么要分代?因为很多对象的生命周期不一致,有的对象朝生夕死new出来之后需要马上进行销毁掉,有的老对象,生命周期就是很短,如果将这些对象放在一起,每一次都需要扫描整个堆的区域,是很麻烦的,那堆时时刻刻都需要做GC的;

堆空间越大,垃圾回收时间会变长,用户基本无感知,那么震哥哥系统就可以在卡顿几乎无感知的情况下一便处理业务一边收集垃圾;

四)G1为什么使用增量更新?

1)增量更新效率更低,因为要从增量节点数据结构的根节点继续向下扫描,G1要是采取扫描的话,你会涉及到很多regin区域的跨代扫描,就会比较麻烦,这个时候跨很多代,遍历的复杂度会更高,增量更新不需要跨很多代,老年代有很多卡表;

2)但是CMS只有一个卡表,STAB只需要标记一下,不需要重新扫描,只需要下一轮GC再次进行回收即可,下一次再去重新去回收垃圾即可,对于G1来说,多一些浮动垃圾也没啥事,因为本身算法很多垃圾对象都不会回收,多一些浮动垃圾也没啥事;

五)G1垃圾回收器的回收过程:

1)初始标记:暂停所有的其他线程,并记录下gcroots直接能引用的对象,速度很快

2)并发标记:如果在并发标记过程中发现某些regin对象的存活率很小甚至于说基本没有对象存活,那么G1就会在这个阶段将整个regin回收

3)重新标记:

4)筛选回收:筛选回收阶段实现针对每一个的Regin的回收价值和成本来进行排序,根据用户所期望的GC停顿时间来制定回收计划,比如说此时老年代有1000个regin都满了,但是因为根据本次停顿时间,本次来及回收可能只是停顿200ms,那么根据之前回收成本计算可知回收其中的800个regin可能只是需要200ms,那么就只会回收800个regin,尽量把GC的停顿时间控制在我们想要的范围内

其实这个过程也是可以和用户线程一起并发执行,但是因为只是回收一部分regin,时间是用户可控制的,而且停顿用户线程可以提升垃圾回收的效率,不管是年轻代还是老年代,回收算法主要采用的是复制算法,将一个regin的存活对象存放到另一个regin中,这种不会像CMS一样回收玩因为还有很多内存碎片需要重新整理一次,G1采用复制算法几乎不会有太多的内存碎片

(注意:CMS回收阶段是跟用户线程一起并发执行的,G1因为内部实现太复杂暂时没实现并发回收,不过到了Shenandoah就实现了并发收集,Shenandoah可以看成是G1的升级版本)

六)G1垃圾回收器的特点:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1147691.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

leetcode-数组

1.二分法手撕704&#xff08;诀窍在于用合法区间判断&#xff09;230810 左闭右闭: while(left<right)合法&#xff0c;middle(leftright)/2, if(nums[middle]>target)说明nums[middle]一定不是我们搜索的值&#xff0c;所以rightmiddle-1; elseif(nums[middle]<targe…

基于单片机的太阳跟踪系统的设计

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 技术交流认准下方 CSDN 官方提供的联系方式 文章目录 概要 一、设计的主要内容二、硬件电路设计2.1跟踪控制方案的选择2.1.1跟踪系统坐标系的选择2.2系统总体设计及相关硬件介绍…

9、电路综合-基于简化实频的任意幅频响应的微带电路设计

9、电路综合-基于简化实频的任意幅频响应的微带电路设计 网络综合和简化实频理论学习概述中的1-8介绍了SRFT的一些基本概念和实验方法&#xff0c;终于走到了SRFT的究极用途&#xff0c;给定任意响应直接综合出微带电路。 1、任意幅频响应的微带电路设计用途 我们演示了采用…

Flask基本教程以及Jinjia2模板引擎简介

flask基本使用 直接看代码吧&#xff0c;非常容易上手&#xff1a; # 创建flask应用 app Flask(__name__)# 路由 app.route("/index", methods[GET]) def index():return "FLASK&#xff1a;欢迎访问主页&#xff01;"if __name__ "__main__"…

【多线程面试题九】、说一说sleep()和wait()的区别

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;说一说sleep()和wait()的…

如何使用 Docker 搭建 Jenkins 环境?从安装到精通

不少兄弟搭 jenkins 环境有问题&#xff0c;有的同学用 window, 有的同学用 mac&#xff0c; 有的同学用 linux。 还有的同学公司用 window, 家里用 mac&#xff0c;搭个环境头发掉了一地。。。 这回我们用 docker 去搭建 jenkins 环境&#xff0c;不管你是用的是什么系统&…

方太描画未来厨房的模样

作者 | 辰纹 来源 | 洞见新研社 不知不觉中&#xff0c;iPhone已经更新到15代了&#xff0c;家里的电视变成了越来越轻薄的液晶屏&#xff0c;过去被称为“老三样”的富康&#xff0c;捷达、桑塔纳&#xff0c;如今也被以特斯拉为代表的新能源智能汽车们所取代…… 类似以上的…

第五章 I/O管理 一、I/O设备的基本概念和分类

目录 一、什么是I/O设备 1、定义&#xff1a; 2、按特性分类&#xff1a; 3、按传输速率分类&#xff1a; 4、按信息交换的方式分类&#xff1a; 二、总结 一、什么是I/O设备 1、定义&#xff1a; I/O设备就是可以将数据输入到计算机&#xff0c;或者可以接收计算机输出…

<C++> vector模拟实现

目录 前言 一、定义命名空间 二、构造函数 三、拷贝构造 四、赋值运算符重载 五、push_back && reserve 六、深拷贝问题 七、iterator 迭代器 1. 可读可写 2. 只读 八、operator[ ] 1. 可读可写 2. 只读 九、insert 问题&#xff1a;内部迭代器失效 十、erase 十一、re…

【网络安全】Seeker内网穿透追踪定位

Seeker追踪定位对方精确位置 前言一、kali安装二、seeker定位1、ngrok平台注册2、获取一次性邮箱地址3、ngrok平台登录4、ngrok下载5、ngrok令牌授权6、seeker下载7、运行seeker定位8、运行隧道开启监听9、伪装链接10、用户点击&#xff08;获取定位成功&#xff09;11、利用经…

(速进)完美解决“用户在命令行上发出了 EULAS_AGREED=1,表示不接受许可协议。”以及“此产品安装程序不支持降级”

安装VMware时候&#xff0c;出现以下两种情况的原因是&#xff1a;未彻底卸载&#xff08;之前安装过VMware&#xff09;&#xff0c;例如&#xff1a;还有相关配置信息、注册表信息等。只要彻底清理就可以解决此问题。 网上很多帖子使用了powershell里的命令 例如&#xff1…

Linux病毒疯狂增长,我们该如何…

导读国家信息中心日前与瑞星联合发布的《2017年上半年中国网络安全报告》&#xff08;以下简称《报告》&#xff09;指出&#xff0c;目前Linux系统病毒已快速增长。《报告》对2017年1至6月的网络安全现状与趋势进行统计、研究和分析后指出&#xff0c;Linux系统的勒索软件数量…

帆软finereport10.0 多个筛选框根据不同条件必须选一个才能查询

效果&#xff1a; 方法一&#xff1a; 方法二&#xff1a; 方法一&#xff1a;在查询里写上一段js&#xff0c;此方法会把端口和IP暴露出来&#xff0c;方法二比较完美。 var diff this.options.form.getWidgetByName("diff").getValue();//正反向 var fllh …

【多线程面试题 八】、说一说Java同步机制中的wait和notify

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;说一说Java同步机制中的…

Day 12 python学习笔记

模块 内置模块 sys模块 概述&#xff1a;Python 的 sys 模块提供访问解释器使用或维护的变量&#xff0c;和与解释器进行交互的函数。通俗来讲&#xff0c;sys 模块为程序与 Python 解释器的交互&#xff0c;提供了一系列的函数和变量&#xff0c;用于操控 Python 运行时的环境…

多输入多输出 | Matlab实现k-means-ELM(k均值聚类结合极限学习机)多输入多输出组合预测

多输入多输出 | Matlab实现k-means-ELM&#xff08;k均值聚类结合极限学习机&#xff09;多输入多输出组合预测 目录 多输入多输出 | Matlab实现k-means-ELM&#xff08;k均值聚类结合极限学习机&#xff09;多输入多输出组合预测预测效果基本描述程序设计参考资料 预测效果 基…

lazarus开发:提升sqlite数据插入速度

目录 1 前言 2 优化数据容器 3 开启事务插入数据 4 其他方面优化 1 前言 近期有一个需求是向数据库中插入excel文件中的10万多条数据&#xff0c;接近70个字段。最初整个插入数据时间是大约40分钟&#xff0c;经过优化调整后&#xff0c;大幅优化为大约5分钟。这里简单介绍…

CV计算机视觉每日开源代码Paper with code速览-2023.10.27

精华置顶 墙裂推荐&#xff01;小白如何1个月系统学习CV核心知识&#xff1a;链接 点击CV计算机视觉&#xff0c;关注更多CV干货 论文已打包&#xff0c;点击进入—>下载界面 点击加入—>CV计算机视觉交流群 1.【基础网络架构&#xff1a;Transformer】&#xff08;Ne…

Jetpack:020-Jetpack导航示例:底部导航栏

文章目录 1. 概念介绍2. 使用方法3. 代码与分析3.1 示例代码3.2 代码分析 4. 内容总结 我们在上一章回中介绍了Jetpack中导航相关的内容&#xff0c;本章回中主要介绍 导航的综合示例&#xff1a;底部导航栏。闲话休提&#xff0c;让我们一起Talk Android Jetpack吧&#xff0…

2-多媒体数据压缩国际标准-Part3

文章目录 视频压缩的国际标准MPEG-1&MPEG-2/H.262视频标准MPEG-4 AVC/H.264视频标准H.264编码框架概述H.264视频编码的技术创新点 H.265/HEVC视频标准HEVC性能与编解码框架概述Quadtree-based coding structureDeblocking & SAO FilterHEVC各模块运算量 视频压缩的国际…