admin管理员组

文章数量:1581020

项目场景:

金融类项目,私募基金直销平台,用户量很少


问题描述

项目上线后系统越来越卡,由于单机部署,运维同学怀疑是资源问题(先反馈给了运维),加了内存和带宽,问题依然没有解决。


原因分析:

生产环境,涉及隐私截图没上!

1、初步试探

jps -l 查看服务pid,找到对应服务。
jstat -gc pid 1000 20 打印GC情况,间隔1S共20次。

20S之内执行了28次YGC和2次FGC,GC时间1S多!
服务重启短短几天FGC执行了六万多次,GC累计时长已达将近6万秒!(特意对比了一下其他项目,加一起都没这么多……)

这个数据着实恐怖,来看一下正常GC的经验值:
YGC 执行时间不超过50ms,执行频率不小于10s每次
FGC 执行时间不超过1s,执行频率不低于10分钟每次

很明显,GC执行频率已经远远超过正常值,顺着这个结果分析,猜测原因大概有两个:
1,内存泄露:代码有严重的问题;
2,内存不够:单机部署,确实扛不住客户量。

review了下提交记录,近期并没有修改代码。内存泄露的对象一般会长期持有回收不掉,随着积累大概率出现内存溢出的情况。但是,这里没有出现内存溢出,只是频繁GC,难道真是内存不够用了?
于是先排除第一种可能,加了内存,重启服务……

2、循循渐进

重启完服务,问题并没有解决,GC频率很快上来了,于是继续分析……

eden区YGC后有100多M的对象直接进入到了old区!
s区扩容,抢占eden内存,但是不足以承载eden区GC后的存活对象,所以有100多M的对象直接进入到了old区。

jmap -heap pid 查看堆信息

eden:s != 8:1 ,s区3.5M,怎么这么小?

jinfo pid 查看JVM配置信息

发现了这个配置:-XX:+UseParallelGC,没错,Java8的默认垃圾回收器paralleGC。而paralleGC有个默认开启的配置:UseAdaptiveSizePolicy,该配置默认开启堆内存new区的自动分配,于是SurvivorRatio就失效了。YGC频率加,eden区会扩容增加占比,s区占比就会被缩减,eden区回收后的存活对象s区放不下就会更快的往old转移,old区对象激增导致FGC频率加快……

于是在启动脚本里添加了-XX:-UseAdaptiveSizePolicy,把动态分配区内存给关了。

3、拨开云雾

等待了一天,看下GC情况:
FGC频率回到了一个正常的值,同时也基本可以确定,s区太小,会导致FGC频率增大。

但是,20S内64次YGC,虽然GC时间短,客户卡顿的感知没那么明显,但这个值还是太高了。

然后再把时间间隔调成100ms,看下情况:
FGC频率回到了一个正常的值,同时也基本可以确定,s区太小,会导致FGC频率增大。

但是,20S内64次YGC,虽然GC时间短,客户卡顿的感知没那么明显,但这个值还是太高了。

然后再把时间间隔调成100ms,看下情况:

FGC频率回到了一个正常的值,同时也基本可以确定,s区太小,会导致FGC频率增大。

但是,20S内64次YGC,虽然GC时间短,客户卡顿的感知没那么明显,但这个值还是太高了。

然后再把时间间隔调成100ms,看下情况:

eden区增的很快,s区空间始终没有空闲出来,FGC频率也上来了。(上午看得时候才12次FGC)
回看下new区的大小:eden区256M,s区42.5M,eden区增的很快,s区的内存始终没清掉,s区是不是太小了?
再回看下堆内存配置:xms: 1G xmx: 3G,初始内存是不是给少了,而且客户只有一台服务器,把初始内存也设成3G?

-Xms3096m 更改初始内存

重启服务,再看下GC情况:

YGC频率降低到20S以上,FGC也正常,然后就又等了一天继续观察GC情况:

FGC增了一次,YGC频率很高。

然后看了下日志,恰巧此时没有人使用,所以就很好奇,哪来这么多对象?
开始怀疑系统是不是有不正常的定时任务,于是查看代码,发现任务都没有打日志!!!我的一口老血啊……最后登录XXLJOB后台,发现任务配置被改了,有很几个任务改成了一两分钟,甚至还有一秒执行一次的(数据同步的任务,数据量还不小。)!!!


解决方案:

问题解决:
1,降低任务的执行频率,因为系统本身用户量不大,签约系统对数据实时性要求不高。
2,和客户沟通下,如果业务对数据实时性要求确实这么高,那么适当放大new区比例,因为数据同步大都是临时对象。

本文标签: 环境系统JVM调优