首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >JVM(四)

JVM(四)

作者头像
小土豆Yuki
发布2021-08-06 14:58:27
7360
发布2021-08-06 14:58:27
举报
文章被收录于专栏:洁癖是一只狗洁癖是一只狗

什么时候触发新生代和老年代的混合垃圾回收

G1有一个参数-XX:InitiatingHeapOccupancyPercent,他的默认是45%,他的含义就是老年代到了45%的时候,就会进行混合回收,比如有2048个region,其中老年代占据了有1000个region,就会混合回收.

G1垃圾回收的具体过程

初始化标记

初始化标记先停止新运行,然后对线程内存中的局部变量代表的GC Roots,以及方法区中的静态变量代表的GC Roots,进行扫描,标记他们的直接引用

并发标记

并发标记系统正常运行,并发标记就是从GC Roots开始最终所有存活对象,由于系统正常运行,此时会记录修改的对象

最终标记

最终标记,系统就会停止运行,根据并发标记阶段记录的那些向修改,最终标记一下那些对象存活,那些垃圾对象

混合回收

最后一个阶段,计算老年代中每个region中存活的对象数量,存活对象占比,还有执行垃圾回收预期性能和效率,此时系统停止运行,全力进行垃圾回收,此时会选择部分region进行回收,因为必须让垃圾回收停顿时间在控制范围内,

例如,老年代有1000个region都满了,预期目标就是200ms的停顿时间,通过计算最大能回收800个region,这样把停顿时间控制在范围内,

说明一点就是老年代达到45%(-XX:InitiatingHeapOccupancyPercent进行设置,默认是45%)的时候,触发的是混合回收,就是说回收老年代和年轻代,以及大对象,

G1垃圾回收重要参数

我们知道G1垃圾回收有几个阶段,最后一个阶段就是混合回收,其实停止所有程序运行,然后在进行全力回收,但是我要注意的是,这个回收可能要反复好几次,反复几次是有-XX:G1MixedGCCountTarget参数控制,默认值8,就会每次回收会反复回收8次,比如我们预期要会搜160个region,因此每次会回收20个region,反复8次就可以回收160region,这样所得好处就是,是系统有间隙执行系统,不会一直停顿,

另外一个参数-XX:G1HeapWastePercent,默认是5%,由于我们的G1回收是基于复制算法进行的,因此他会把存活的而对象复制到另外一个region,然后一次性清理有垃圾的region,而这个参数的作用就是混合回收的空闲region达到堆内存的5%的时候,就会停止混合回收,意味回收就结束了,

另外一个参数“-XX:G1MixedGCLiveThresholdPercent 默认是85%,作用就是要回收的region存活的对象必须低于85%才会被回收,不然存活对象大于85%,回收他成本很高

回收失败的情况

当然我们知道,复制算法,是要把存活的对象复制到另外一个region,但是如果没有空闲的region可以存放存活的对象,就会触发失败,一旦失败,就会停止系统程序,然后采用单线程进行标记,清理,压缩整理,空闲一批region,切记这个过程很慢

G1垃圾回收中如何触发新生代GC

背景是堆内存是4G,一共2048个region,每个region是2M,其中新生代开始占5%,也就是100region,新生代200M,假设系统每秒产生3M,则一分钟新生代Eden几乎就满了,这里我就想起以前我们记得是当Eden满的时候触发GC,

但是G1,不是这样的,因为如果此时回收这200M内存消耗几十毫秒,而我们记得参数-XX:MaxGCPauseMills=200ms,和我们预期的相差太远

而且这样回收回到每分钟就会发生一个新生代GC,频繁的发生GC,是没有这个必要的,因此不如在此时给新生代再分配一些region,然后新生代继续分配对象,最后G1发现回收300m内存需要消耗200ms,那这个时候触发一次新生代GC,是最好的,这个我们要明白G1是很灵活的,他会根据你设定的gc停顿时间给你的新生代不停的分配region,到的一定程度,就会触发新生代GC,保证在预期的时间范围内。大致思想就是上面这些,但是具体还要根据实际情况才知道.

mixed GC如何优化

mixed GC是当老年代占堆内存超过45%的时候就会触发,这mixed gc优化的核心不是参数的优化,是如何让新生代不会进入老年代,所以最重要的还是我们之前说的参数-XX:MaxGCPauseMills参数,如果设置大了,就会新生代达到60%才会触发新生代GC,且存活的对象就会很多,而此时Suvivor放不下对象,就会进入老年代,所以要保证-xx:MaxGCPauseMills参数既要保证新生代不要频繁的gc,还要保证存活的对象有多少,避免存活对象太多进入老年代,频繁发生Mied GC

运行的系统,怎么会卡顿呢

我们的系统正常运行,对象不断的产生,当新生代Eden块要满的时候,就会发生垃圾回收,此时就会把存活的对象放到S1,那些是存活的对象就是GC Roots引用的对象,如类的静态变量和实例变量,被这些对象引用,就是存活的对象,

更重要的是系统此时是对外是停止运行,这个就是Stop the World,就会导致系统卡顿的问题,

新生代gc对系统的卡顿的影响

一般我们新生代进行GC,如果内存足够,几个小时进行新生代GC,高峰期最多也就几分钟一次新生代GC,通常新生代复制算法效率很高,因此一般情况下,只有少数的对象,然后进行回收对系统影响很小

但是如果你的机器是一个32核64G的机器,分给堆内存大概就有几十GC,Eden可能有30-40的内存,

正好的你使用了kafak,elasticserch之类的大数据系统,部署在大内存机器中,每秒几万的请求,就可能导致几十G内存发生频发内存发生,假设1分钟会塞满一次,每次GC,都会消耗几百毫秒,甚至1秒,就会导致你的系统卡顿,这个频繁的卡顿,对用户影响极大

如何解决大内存新生代GC过慢的问题

其实遇到大内存的机器GC,我们肯定就想到了G1垃圾收集器,G1就是为了大内存机器垃圾回收慢的问题场景提供的,

G1预估系统停顿的时候,让垃圾在合理的时间内进行回收,完美的解决了停顿时间过程的问题,同时我们要知道频繁老年代GC的问题

前面我们讲过新生代gc问题不大,问题是频繁的老年代GC问题,我们也讲过进入老年代的几个条件就是,年龄多大,新生代的survivor存活对象太多,无法进入Survivor中,进入老年代,还有就是动态年龄判定规则,suvivor区域几个年龄对象加起来超过Survivor的50%

我们要知道老年代的GC是非常慢的,比如新生代一次GC消耗200ms,对用户影响不大,但是老年代耗费2s,就会导致页面卡顿2s,影响很大的,根本解决问题就是尽可能不让对象进入老年代.

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-08-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 洁癖是一只狗 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档