踩坑调优,一次cpu引发的调优

      紧急处理   

 问题产生,用户反馈环境变慢,经常超时,同时收到了监控短信,提示cpu太高,。。。。开始定位吧,先简单看一下jps -m -l -v 看到这台机器上跑了好几个进程。

top一下 找到cpu最高的进程   发现是18463  ,

      第一感觉是代码有问题了,是不是某种条件下有死循环了,或者突然有什么地方出现了大量运算,于是想找出对应线程18463中消耗cpu最高的线程。命令:top -Hp 18463 找出cpu最高的两个线程

 PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND

18466 root      20   0 9593m 5.7g 5368 R 88.7 36.4  21:41.82 zzb_item_pc12                                                         

18467 root      20   0 9593m 5.7g 5368 R 76.2 36.4  21:27.85 zzb_item_pc12

大部分cpu都是这两个线程消耗的,小样终于出来了吧,下面就是常规操作,找到对应线程,看看对应的代码是不是有死循环。

命令  printf "%x\n" 18466  4822       printf "%x\n" 18467  4823  看看对应的十六进制的jstack中是什么线程,[root@jstwqt6hx9va2c app]# jstack 18463 |grep 4822
"GC task thread#0 (ParallelGC)" os_prio=0 tid=0x00007f9df001e000 nid=0x4822 runnable 
[root@jstwqt6hx9va2c app]# ^C
[root@jstwqt6hx9va2c app]# jstack 18463 |grep 4823

"GC task thread#1 (ParallelGC)" os_prio=0 tid=0x00007f9df001f800 nid=0x4823 runnable 

     峰回路转

    从上面jstack中看,并没有我预期的jstack中的***Class 正在运行,看来预测失误,可能不是死循环,那么不妨将整个jstack保存,以防丢失现场数据。其实当时看top命令的时候就可以看出来,不单单是cpu高,内存也高,应该想到是GC导致的。不说了,继续分析。

       现在的问题是gc高了,怎么办,还没有达到触发gc配置文件写dump的条件,那么值能jmap上了,一般情况下是直接先打印一个heap的使用情况,发现内存的新生代和老生代都满了特别是老生代99.99200575782108% used

如果想具体看内存中的信息需要dump一份内存,命令参考 $jmap –dump:live,format=b,file=aaa.bin 18463 ,当时我懒了一下没有去dump一份,一来线上环境dump慢,第二个如果是自动挂了,启动参数中会自动dump会,不用我费心。后来证明我错了,不应该懒,后来发现自动好了,dump内容没有了,错过了一次发现代码问题的机会了。

   这时候明细是发现gc引发的cpu高,立马想到fullgc是不是太频繁了,jstat -gcutil  18463 5000   ,或者jatat -gc 18463 5000

[root@jstwqt6hx9va2c app]# jstat -gc 18463 5000
 S0C    S1C    S0U    S1U      EC       EU        OC         OU       MC     MU    CCSC   CCSU   YGC     YGCT    FGC    FGCT     GCT   
454144.0 198656.0  0.0    0.0   465920.0 465796.4 2796544.0  2796495.9  95872.0 83223.1 10112.0 7958.7   4157  296.165  939  3765.344 4061.509
454144.0 198656.0  0.0    0.0   465920.0 465815.1 2796544.0  2796243.2  95872.0 83223.1 10112.0 7958.7   4157  296.165  940  3770.210 4066.375
454144.0 198656.0  0.0    0.0   465920.0 465910.4 2796544.0  2796418.8  95872.0 83223.1 10112.0 7958.7   4157  296.165  942  3777.316 4073.481
454144.0 198656.0  0.0    0.0   465920.0 465875.6 2796544.0  2796387.2  95872.0 83223.1 10112.0 7958.7   4157  296.165  943  3780.453 4076.619
454144.0 198656.0  0.0    0.0   465920.0 465920.0 2796544.0  2796387.2  95872.0 83223.1 10112.0 7958.7   4157  296.165  944  3786.689 4082.854

454144.0 198656.0  0.0    0.0   465920.0 465889.6 2796544.0  2796387.2  95872.0 83223.1 10112.0 7958.7   4157  296.165  945  3791.030 4087.196

从结果来看打印的这段时间内YGC没有增加,就说明没有进行young gc ,而FGC,名字增加很快,(此时过了几分钟),从939变成了945,说明这么几秒中内进行了6次FullGc,如果没有配置gc的回收机制的情况下用的串行回收器,fullgc是会影响所有线程,gc频繁就会占用大量的cpu时间片,从而导致其他服务变慢,超时等。

       怎么样解决这种young gc机会不变,但是fullgc一直在涨的情况呢。结合内存模型,参考了知乎的一个解答,应该是这种younggc触发fullgc,但是fullgc又无法满足younggc的大小,于是又来一次fullgc。或者说本身的内存配置模型配置的比例不是很好导致的,这个暂时先不管,看看知乎的说法:

 

作者:RednaxelaFX
链接:https://www.zhihu.com/question/57097660/answer/152201850
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
 

就光从题主原本的问题描述里给出的jstat -gcutil信息来看,可以猜测题主用的GC是ParallelScavenge(-XX:+UseParallelGC,在server class machine上这个是默认GC;以及有可能full GC用的是PSCompact,不过那对这个问题不重要)。

ParallelScavenge有个默认打开的功能叫做adaptive size policy,在应用分配内存压力很大的时候有可能会把两个survivor space都收缩到最小(几乎为0),于是young gen基本上就整个都是eden,经历young GC能存活下来的对象就会直接晋升到old gen去,等到full GC的时候再看能不能回收。
题主给出的 jstat -gcutil 的空间占用数据似乎是反映了这种情况。

而ParallelScavenge在触发GC的时候,要么会触发单独的young GC,要么会触发young GC + full GC(这里是full GC前会关联触发一次young GC,这个行为由 -XX:+ScavengeBeforeFullGC 参数控制)。在触发full GC的时候,它有可能一口气循环接连触发多次full GC——如果跑了一次full GC还没回收到足够内存,那么会再“用力”一点再触发一次full GC,不行就再“用力”一点…
(“用力”例如说ParallelScavenge的默认策略一开始是不会强迫清理SoftReference的,但需要再“用力”一点的时候就会清理SoftReference。)
题主给出的 jstat -gcutil 的GC次数数据似乎是反映了这种情况。

所以即便不看别的信息,光从这个日志看,大致能推测出题主的应用的GC压力太大了。给它增加一点空间通常能缓解问题。
然后能做个heap dump分析一下到底是啥造成压力大自然是最吼。题主已经做了这个分析,这就很好。

      上面是只会的说法,看完之后,感觉是不是先调整一下gc的回收策略试试效果,先设置一个并发手机器,

     

 -XX:+UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=5

UseConcMarkSweepGC 表示这只并发收集器   

UseCMSCompactAtFullCollection   打开对年老代的压缩。可能会影响性能,但是可以消除碎片 

CMSFullGCsBeforeCompaction  由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。

可以参考: https://blog.csdn.net/rickyit/article/details/53895060

在设置完上述启动参数后观察,发现fullgc的量减少了很多,但是younggc的量增加了不少。而且没有再出现cpu高,内存高的问题,再观察一段时间后继续补充。最后悔的就是没有dump当时内存情况看看到底是什么占用最大的内存。

 

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据引用\[1\]和引用\[2\]的内容,当使用React的useEffect钩子时,如果在useEffect的依赖数组中包含了一个状态变量,那么在该状态变量发生变化时,useEffect的回调函数会被执行。然而,如果在第一次渲染时,该状态变量的值没有发生变化,那么useEffect的回调函数将不会被执行。 如果你希望在第一次渲染时也执行useEffect的回调函数,可以使用一个自定义的hook,如引用\[3\]中的useEffectSkipFirst。这个自定义hook可以跳过第一次渲染时的useEffect回调函数的执行,从而实现在第一次渲染时也执行useEffect的目的。 综上所述,如果你想让React的useEffect在第一次渲染时也执行,可以使用自定义的hook来实现。 #### 引用[.reference_title] - *1* [react 使用 useEffect 及](https://blog.csdn.net/m0_46995864/article/details/122773898)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [React hook 判断语句内不能使用useEffect(乱序问题)](https://blog.csdn.net/weixin_50236973/article/details/123812216)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [react hook 初次渲染时不执行useEffect](https://blog.csdn.net/qq_40657321/article/details/129419133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值