写点什么

JVM-GC- 耗时频频升高,这次排查完想说:还有谁,nginx 作用和工作原理

用户头像
极客good
关注
发布于: 刚刚

降低 abortable preclean 时间,而且不增加 final remark 的时间(因为 remark 是 STW 的)。

5. JVM 参数调优

5.1 第一次调优

先尝试调低 abortable preclean 阶段的时间,看看效果。


有两个参数可以控制这个阶段何时结束:


  • -XX:CMSMaxAbortablePrecleanTime=5000 ,默认值 5s,代表该阶段最大的持续时间

  • -XX:CMSScheduleRemarkEdenPenetration=


【一线大厂Java面试题解析+核心总结学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


50 ,默认值 50%,代表 Eden 区使用比例超过 50%就结束该阶段进入 remark


调整为最大持续时间为 1s,Eden 区使用占比 10%,如下:


-XX:CMSMaxAbortablePrecleanTime=1000


-XX:CMSScheduleRemarkEdenPenetration=10


为什么调整成这样两个值,我们是这样考虑的:首先每次 CMS 都发生在老年代使用占比达到 80%时,因为这是由下面两个参数决定的:


-XX:CMSInitiatingOccupancyFraction=80


-XX:+UseCMSInitiatingOccupancyOnly


而老年代的增长是由于部分对象在 Minor GC 后仍然存活,被晋升到老年代,导致老年代使用占比增长的,也就是在每次 CMS GC 发生之前刚刚发生过一次 Minor GC,所以在那一刻新生代的使用占比是很低的。那么我们预计这个时候尽快结束 abortable preclean 阶段,在 remark 时就不需要扫描太多的 Eden 区对象,remark STW 的时间也就不会太长。


调整的思路是这样了,那到底效果如何呢?


第一次调整的的结果



在统计期间(17 小时左右)内,发生过 2 次 CMS GC。Abortable Preclean 平均耗时 835ms,这是预期内的。但是 Final Remark 平均耗时 495ms(调整前是 112ms),其中一次是 80ms,另一次是 910ms!将近 1 秒钟!Remark 是 STW 的!对于要求低延时的应用来说这是无法接受的!


对比这两次 CMS GC 的详细 GC 日志,我们发现了一些对分析问题非常有用的东西。


remark 耗时 80ms 的那次 GC 日志



[YG occupancy: 181274 K (1887488 K)] - 年轻代当前占用情况和总容量


耗时 80ms 的这次 remark 发生时(早上 9 点,非高峰时段),新生代(YG)占用 181.274M。


remark 耗时 910ms 的那次 GC 日志



[YG occupancy: 773427 K (1887488 K)]


耗时 910ms 的这次 remark 发生时(晚上 10 点左右,高峰时段),新生代(YG)占用 773.427M。因为这个时候高峰期,新生代的占用量上升的非常快,几乎同样的时间内,非高峰时段仅上升到 181M,但是高峰时段就上升到 773M。


这里能得出一个有用的结论:如果 abortale preclean 阶段时间太短,随后在 remark 时,新生代占用越大,则 remark 持续的时间(STW)越长。


这就陷入了两难了,不缩短 abortale preclean 耗时会报 longgc;缩短的话,remark 阶段又会变长,而且是 STW,更不能接受。


对于这种情况,CMS 提供了 CMSScavengeBeforeRemark 参数,尝试在 remark 阶段之前进行一次 Minor GC,以降低新生代的占用。


-XX:+CMSScavengeBeforeRemark


Enables scavenging attempts before the CMS remark step. By default, this option is disabled.

5.2 第二次调优

调优前的考虑:增加-XX:+CMSScavengeBeforeRemark 不是没有代价的,因为这会增加一次 Minor GC 停顿。所以这个方案好或者不好的判断标准就是:增加 CMSScavengeBeforeRemark 参数之后的 minor GC 停顿时间 + remark 停顿时间如果比增加之前的 remark GC 停顿时间要小,这才是好的方案。


第二次调整的结果



在统计期间(20 小时左右)内,发生 3 次 CMS GC。Abortable preclean 平均耗时 693ms。Final remark 平均耗时 50ms,最大耗时 60ms。Final remark 的时间比调优前的平均时间(112ms)更低。


那么 CMS GC 前的 Minor GC 停顿时间又如何呢?来看看详细的 GC 日志。


3 次 CMS GC remark 前的 Minor GC 日志分析


第 1 次是非高峰时段的表现,Minor GC 耗时 0.01s + remark 耗时 0.06s = 0.07s = 70ms,如下



第 2 次是高峰时段,Minor GC 耗时 0.01s + remark 耗时 0.05s = 0.06s = 60ms,如下



第 3 次是非高峰时段,Minor GC 耗时 0.00s + remark 耗时 0.04s = 0.04s = 40ms,如下



所以,3 次 Minor GC + remark 耗时的平均耗时 < 60ms,这比第一次调优时 remark 平均耗时 495ms 好得多了。

6.优化结果

至此,我们最初的目标- 降低 abortable preclean 时间,而且不增加 final remark 的时间 ,已经达到了。甚至 remark 的时间也缩短了。

7. 小结

解决 abortable preclean 时间过长的方案可以归结为两步:


  • 缩短 abortable preclean 时长,通过调整这两个参数:

用户头像

极客good

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
JVM-GC-耗时频频升高,这次排查完想说:还有谁,nginx作用和工作原理