某系统反馈『性能抖动,响应时间会突然飙高,TP999 MAX会到3000+』,初步怀疑是JVM FULL GC导致的 STW,观察FULL GC日志默认的JVM参数:

-Xms4096m -Xmx4096m -XX:PermSize=512M -XX:MaxPermSize=512M -XX:ReservedCodeCacheSize=1024M -XX:+UseCodeCacheFlushing

从线上down下来的GC LOG如下:

1768.617: [GC [PSYoungGen: 1313280K->31072K(1341440K)] 3990240K->2729238K(4137984K), 0.0992420 secs] [Times: user=0.36 sys=0.01, real=0.10 secs]
1770.525: [GC [PSYoungGen: 1316704K->27632K(1345536K)] 4014870K->2750306K(4142080K), 0.0552640 secs] [Times: user=0.20 sys=0.00, real=0.06 secs]
1772.437: [GC [PSYoungGen: 1319408K->51424K(1343488K)] 4042082K->2795338K(4140032K), 0.0578170 secs] [Times: user=0.23 sys=0.00, real=0.06 secs]
1774.583: [GC [PSYoungGen: 1343200K->30912K(1340416K)] 4087114K->2796362K(4136960K), 0.0746000 secs] [Times: user=0.27 sys=0.00, real=0.07 secs]
1776.521: [GC [PSYoungGen: 1316535K->27328K(1341952K)] 4081986K->2817152K(4138496K), 0.0792640 secs] [Times: user=0.26 sys=0.01, real=0.08 secs]
1776.601: [Full GC [PSYoungGen: 27328K->0K(1341952K)] [ParOldGen: 2789824K->150473K(2796544K)] 2817152K->150473K(4138496K)
[PSPermGen: 60521K->60480K(524288K)], 0.5549000 secs] [Times: user=1.64 sys=0.00, real=0.55 secs]
1779.045: [GC [PSYoungGen: 1285632K->51105K(1334784K)] 1436105K->201578K(4131328K), 0.0313710 secs] [Times: user=0.12 sys=0.00, real=0.03 secs]
1781.122: [GC [PSYoungGen: 1330593K->30368K(1338880K)] 1481066K->202953K(4135424K), 0.0522210 secs] [Times: user=0.17 sys=0.00, real=0.05 secs]
1782.995: [GC [PSYoungGen: 1309856K->27488K(1341440K)] 1482441K->223926K(4137984K), 0.0416840 secs] [Times: user=0.13 sys=0.01, real=0.04 secs]
.
.
.
2007.041: [GC [PSYoungGen: 1328928K->27808K(1351168K)] 4059412K->2783016K(4147712K), 0.0694050 secs] [Times: user=0.24 sys=0.00, real=0.07 secs]
2008.972: [GC [PSYoungGen: 1330848K->47079K(1350144K)] 4086056K->2827611K(4146688K), 0.0648990 secs] [Times: user=0.23 sys=0.00, real=0.07 secs]
2009.037: [Full GC [PSYoungGen: 47079K->0K(1350144K)] [ParOldGen: 2780532K->191662K(2796544K)] 2827611K->191662K(4146688K)
[PSPermGen: 60530K->60530K(524288K)], 3.4921610 secs] [Times: user=13.39 sys=0.08, real=3.49 secs]
2014.630: [GC [PSYoungGen: 1303040K->31712K(1328640K)] 1494702K->223374K(4125184K), 0.0672680 secs] [Times: user=0.21 sys=0.00, real=0.07 secs]
2016.521: [GC [PSYoungGen: 1312223K->27136K(1339392K)] 1503886K->243740K(4135936K), 0.0297230 secs] [Times: user=0.09 sys=0.00, real=0.03 secs]
2018.442: [GC [PSYoungGen: 1307632K->47901K(1335296K)] 1524236K->285700K(4131840K), 0.0524640 secs] [Times: user=0.18 sys=0.00, real=0.05 secs]
2020.530: [GC [PSYoungGen: 1325341K->30272K(1337856K)] 1563140K->289717K(4134400K), 0.0615270 secs] [Times: user=0.22 sys=0.00, real=0.06 secs]

分析上述日志,可以看出两个问题:

1. 每次ygc,晋升至老年代的对象体积较大,平均为20m+,这导致fgc频率较高;

2. FGC的时间很长,上面看到的是550ms,实际上还有2000+的,这导致FGC开销很大;

因而调优思路很明确:

1. 减少每次ygc晋升大小;

2. 尽可能的减少每次fgc的时间开销;

因而进行了如下的尝试:

一. 使用parallel scavenge GC,但是加入如下参数 :

-Xmn1350m -XX:-UseAdaptiveSizePolicy  -XX:SurvivorRatio=6
         调优思路:
               ygc每次晋升到old gen的内容较多,而这很可能是因为JVM 动态的调整eden 和 survivor区,导致它们空间过小,部分本该在new gen呆着的对象直接跳到old gen

了(此现象在survivor区较为明显,因为其本来就较小)

调优效果:

可以看到调优后full gc频率大为减少(由4min一次--->变为30h一次),同时因为少了 频繁调整new gen的开销,ygc耗时也略微减少了.

遗留问题:

虽然fgc频率大为降低,但是每次fgc的耗时还是一样,500ms+~2000ms

二. 改用传说中的 CMS GC,加入jvm参数如下(原来的配置不变):

-XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+UseCMSInitiatingOccupancyOnly
       -XX:CMSInitiatingOccupancyFraction=70
      调优思路:
           使用CMS GC,启用碎片整理,降低fgc的耗时

调优效果:

遗留问题:

91832.693: [GC [1 CMS-initial-mark: 1968357K(2811904K)] 2123963K(4021504K), 0.0732300 secs] [Times: user=0.06 sys=0.01, real=0.08 secs]
91832.767: [CMS-concurrent-mark-start]
91834.022: [CMS-concurrent-mark: 1.256/1.256 secs] [Times: user=4.06 sys=0.94, real=1.25 secs]
91834.022: [CMS-concurrent-preclean-start]
91834.040: [GC91834.040: [ParNew: 1091621K->50311K(1209600K), 0.0469420 secs] 3059979K->2018697K(4021504K), 0.0473540 secs] [Times: user=0.16 sys=0.01, real=0.05 secs]
91834.123: [CMS-concurrent-preclean: 0.051/0.101 secs] [Times: user=0.31 sys=0.05, real=0.10 secs]
91834.123: [CMS-concurrent-abortable-preclean-start]
91834.900: [CMS-concurrent-abortable-preclean: 0.769/0.777 secs] [Times: user=2.36 sys=0.53, real=0.78 secs]
91834.903: [GC[YG occupancy: 595674 K (1209600 K)]91834.904: [Rescan (parallel) , 0.6762340 secs]
91835.580: [weak refs processing, 0.0728400 secs]91835.653: [scrub string table, 0.0009380 secs]
[1 CMS-remark: 1968386K(2811904K)] 2564060K(4021504K), 0.7555510 secs] [Times: user=2.73 sys=0.03, real=0.76 secs]
91835.659: [CMS-concurrent-sweep-start]
91836.401: [GC91836.401: [ParNew: 1087111K->47187K(1209600K), 0.0723650 secs] 2884822K->1844924K(4021504K), 0.0727230 secs] [Times: user=0.26 sys=0.00, real=0.07 secs]
91837.799: [GC91837.800: [ParNew: 1083987K->45402K(1209600K), 0.0663740 secs] 2609145K->1570570K(4021504K), 0.0667940 secs] [Times: user=0.23 sys=0.01, real=0.07 secs]
91839.374: [GC91839.374: [ParNew: 1082202K->45240K(1209600K), 0.0673220 secs] 2353716K->1316904K(4021504K), 0.0677680 secs] [Times: user=0.23 sys=0.00, real=0.07 secs]
91840.710: [GC91840.710: [ParNew: 1082040K->19453K(1209600K), 0.0215620 secs] 2188694K->1126165K(4021504K), 0.0219340 secs] [Times: user=0.06 sys=0.01, real=0.02 secs]
91842.338: [GC91842.338: [ParNew: 1056253K->52429K(1209600K), 0.0507020 secs] 1780994K->777227K(4021504K), 0.0511040 secs] [Times: user=0.19 sys=0.00, real=0.05 secs]
91843.636: [GC91843.636: [ParNew: 1089229K->21084K(1209600K), 0.0408210 secs] 1657456K->589323K(4021504K), 0.0412140 secs] [Times: user=0.13 sys=0.00, real=0.05 secs]
91845.222: [GC91845.223: [ParNew: 1057884K->42762K(1209600K), 0.0419470 secs] 1315163K->300052K(4021504K), 0.0423230 secs] [Times: user=0.13 sys=0.00, real=0.04 secs]
91845.925: [CMS-concurrent-sweep: 9.875/10.266 secs] [Times: user=31.77 sys=6.94, real=10.26 secs]
91845.936: [CMS-concurrent-reset-start]
91845.985: [CMS-concurrent-reset: 0.049/0.049 secs] [Times: user=0.16 sys=0.03, real=0.05 secs]

oldgen gc开销还是较大,虽然比ps gc略好,而且通过gc日志发现,主要耗时都是在remark的rescan阶段

三. 降低remark的时间开销,加入参数:-XX:+CMSScavengeBeforeRemark

调优思路:

通常情况下进行remark会先对new gen进行一次扫描,而且这个开销占比挺大,所以加上这个参数,在remark之前强制进行一次ygc

调优效果:

直接看日志吧,从下面日志看到remark的时间缩短的了很多。

 91718.963: [GC [ CMS-initial-mark: 1968409K(2811904K)] 2019966K(4021504K), 0.0419650 secs] [Times: user=0.02 sys=0.01, real=0.04 secs]
91719.005: [CMS-concurrent-mark-start]
91720.142: [CMS-concurrent-mark: 1.137/1.137 secs] [Times: user=3.72 sys=0.83, real=1.14 secs]
91720.142: [CMS-concurrent-preclean-start]
91720.183: [CMS-concurrent-preclean: 0.041/0.041 secs] [Times: user=0.13 sys=0.03, real=0.04 secs]
91720.183: [CMS-concurrent-abortable-preclean-start]
91720.525: [GC 91720.525: [ParNew: 1074573K->72397K(1209600K), 0.0613610 secs] 3042982K->2040991K(4021504K), 0.0617860 secs]
[Times: user=0.23 sys=0.00, real=0.06 secs]
91721.314: [CMS-concurrent-abortable-preclean: 1.063/1.131 secs] [Times: user=3.59 sys=0.82, real=1.13 secs]
91721.316: [GC[YG occupancy: K ( K)][GC2017--25T19::47.124+: 91721.317: [ParNew: 657780K->30915K(1209600K), 0.1393790 secs]
2626374K->1999535K(4021504K), 0.1398100 secs] [Times: user=0.52 sys=0.00, real=0.14 secs]
91721.456: [Rescan (parallel) , 0.0302040 secs]91721.487: [weak refs processing, 0.0691870 secs]
91721.556: [scrub string table, 0.0009370 secs] [ CMS-remark: 1968619K(2811904K)] 1999535K(4021504K), 0.2452990 secs] [Times: user=0.72 sys=0.00, real=0.25 secs]
91721.562: [CMS-concurrent-sweep-start][CMS-concurrent-sweep: 8.561/8.898 secs] [Times: user=27.82 sys=5.98, real=8.89 secs]
[CMS-concurrent-reset-start]

至此,jvm调优告一段落,目前线上大约30H生一次 CMS GC(“FGC”),每次耗时在300ms以内,算是比较完美了。

JVM参数如下:

-Xms4096m -Xmx4096m -XX:PermSize=256M -XX:MaxPermSize=256M -XX:ReservedCodeCacheSize=1024M -XX:+UseCodeCacheFlushing

-Xmn1350m -XX:-UseAdaptiveSizePolicy  -XX:SurvivorRatio=6 -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+UseCMSInitiatingOccupancyOnly     -XX:CMSInitiatingOccupancyFraction=70  -XX:+CMSScavengeBeforeRemark

JVM调优之---一次GC调优实战的更多相关文章

  1. JVM系列(四)之GC调优

    JVM内存参数调优 为什么要GC调优? 或者说的更确切一些,对于基于Java的服务,是否有必要优化GC?应该说,对于所有的基于Java的服务,并不总是需要进行GC优化,但当你的系统时常报了内存溢出或者 ...

  2. JVM 配置常用参数和常用 GC 调优策略

    链接:https://juejin.im/post/5c94a123f265da610916081f   JVM 配置常用参数 堆参数 回收器参数 如上表所示,目前主要有串行.并行和并发三种,对于大内 ...

  3. Java GC 专家系列3:GC调优实践

    本篇是”GC专家系列“的第三篇.在第一篇理解Java垃圾回收中我们学习了几种不同的GC算法的处理过程,GC的工作方式,新生代与老年代的区别.所以,你应该已经了解了JDK 7中的5种GC类型,以及每种G ...

  4. 管中窥豹——从对象的生命周期梳理JVM内存结构、GC调优、类加载、AOP编程及性能监控

    如题,本文的宗旨既是透过对象的生命周期,来梳理JVM内存结构及GC相关知识,并辅以AOP及双亲委派机制原理,学习不仅仅是海绵式的吸收学习,还需要自己去分析why,加深对技术的理解和认知,祝大家早日走上 ...

  5. 深入JVM系列(二)之GC机制、收集器与GC调优

    一.回想JVM内存分配 须要了解很多其它内存模式与内存分配的,请看 深入JVM系列(一)之内存模型与内存分配 1.1.内存分配: 1.对象优先在EDEN分配 2.大对象直接进入老年代  3.长期存活的 ...

  6. JVM GC调优一则--增大Eden Space提高性能

    版权声明:本文为横云断岭原创文章,未经博主同意不得转载.微信公众号:横云断岭的专栏 https://blog.csdn.net/hengyunabc/article/details/24924843 ...

  7. 深入JVM系列(二)之GC机制、收集器与GC调优(转)

    一.回顾JVM内存分配   需要了解更多内存模式与内存分配的,请看 深入JVM系列(一)之内存模型与内存分配 1.1.内存分配: 1.对象优先在EDEN分配2.大对象直接进入老年代 3.长期存活的对象 ...

  8. JVM GC调优一则–增大Eden Space提高性能

    缘起 线上有Tomcat升级到7.0.52版,然后有应用的JVM FullGC变频繁,在高峰期socket连接数,Cpu使用率都暴增. 思路 思路是Tomcat本身的代码应该是没有问题的,有问题的可能 ...

  9. GC参考手册 —— GC 调优(基础篇)

    GC调优(Tuning Garbage Collection)和其他性能调优是同样的原理.初学者可能会被 200 多个 GC参数弄得一头雾水, 然后随便调整几个来试试结果,又或者修改几行代码来测试.其 ...

随机推荐

  1. MVC+WCF框架下广告位管理——文件上传

    广告位是站点中不可缺少的内容之中的一个.也是能直接给我们站点带来经济收益的内容之中的一个. 好的广告位不仅不会强宾压主,而会为我们的站点锦上添花.起到画龙点睛的作用.因此设计好广告位也是开发过程中一大 ...

  2. Generate BKS File( Bouncy Castle KeyStore)

    echo "Enter BKS output file name : \c" read filename echo "Enter BKS Password : \c&qu ...

  3. 一张图弄明确开源协议-GPL、BSD、MIT、Mozilla、Apache和LGPL 之间的差别

    导读 在开源软件中常常看到各种协议说明.GPL.BSD.MIT.Mozilla.Apache和LGPL. - 这些协议之间的有什么差别 - 怎样选择合适的开源协议 请看下文,特作记录一篇,以供兴许查看 ...

  4. 〖Android〗Nexus 7 flo (razor) 刷入Recovery/CM-11.0后卡在开机动画的解决方法

    操作日志: 起因:Nexus 7 flo 华硕平板,刷了一个CWM Recovery之后变成了砖机: 尝试1:使用CWM Recovery清除数据,开机失败 尝试2:刷入CM 11 Snapshot的 ...

  5. django之创建第11个项目-页面整合

    目的:将如下众多html页面整合到一个index.html页面中. 百度云盘:django之创建第11个项目-页面整合 用下面的方式实现: <!DOCTYPE html> <head ...

  6. mongobooster 的使用

    mongobooster是mongodb的客户端工具 1.配置数据库 file->connect..->from URL 2.数据查询 选中数据库名,右击-Open Shell->输 ...

  7. RHEL7-openldap安装配置二(客户端安装配置)

    LDAP用户登录流程: 当在客户端输入账号登录系统时,系统根据/etc/nsswitch.conf配置文件获取账号查找顺序,然后再根据PAM配置文件调用相关模块,对账号(/etc/passwd)及密码 ...

  8. Android(4.0.3+): Service, AsyncTask, 定时任务和UI通信

    Service使用AlarmManager实现后台定时任务 在Android 4.0.3版本中, 使用AlarmManager实现后台定时任务是比较好的方案, 其实现机制, 是利用Service的 o ...

  9. Easyui + asp.net MVC 系列教程 第19-23 节 完成注销 登录限制过滤 添加用户

    前面视频 文章地址 Easyui + asp.net MVC 系列教程 第09-17 节 完成登录 高清录制  Easyui + asp.net mvc + sqlite 开发教程(录屏)适合入门  ...

  10. 用dockerfile构建基于centos系统的jar包的镜像

    实际示例: [root@master01 home-dataline]# ls dataline.jar Dockerfile jdk-8u181-linux-x64.tar.gz [root@mas ...