记录一次生产jvm问题的排查

记录一次生产问题的排查

第一天晚上

现象

1、前援反馈页面有接口陆续出现请求超时

2、登录后台服务器top命令查看发现java进程发生高cpu占用情况

3、查看对应业务日志,报数据库连接等待超时-数据库连接池连接无空闲
对应处理

1、临时调大数据库连接池最大连接数限制,从20调整到50

2、重启服务,先保证业务可用

第二天

观察服务器指标

1、free -h 查看内存使用情况,java进程占用高内存

2、查看进程gc情况,jstat -gc 2773947 1000 10,因为该项目没有打印GC日志只能这样临时观察。查看GC日志,

依次是

S0C:幸存0区容量(约350M)、

S1C:幸存1区容量(约350M)、

S0U:幸存0区已使用(201M)、

S1U:幸存1区已使用(0M因为是年轻代用-XX:+UseParNewGC,复制算法)

新生代内存按照8:1:1的比例分为一个eden区和两个survivor(survivor0,survivor1)区。一个Eden区,两个 Survivor区(一般而言)。大部分对象在Eden区中生成。回收时先将eden区存活对象复制到一个survivor0区,然后清空eden区,当这个survivor0区也存放满了时,则将eden区和survivor0区存活对象复制到另一个survivor1区,然后清空eden和这个survivor0区,此时survivor0区是空的,然后将survivor0区和survivor1区交换,即保持survivor1区为空, 如此往复

EC:伊甸区容量350M

EU:伊甸区已使用97M

OC:老年代容量4194M

OU:老年代已使用2878M

MC:元空间大小213M,jdk1.8之前叫永久代

MU:元空间已使用196M

CCSC:压缩类空间大小;(暂不知道用处)

CCSU:压缩类空间使用大小;(暂不知道用处)

YGC:年轻代gc 4786

FGC:老年代GC(可以看下图,这是两次GC日志的对比,才短短几分钟就出现了两次Full GC,而且查看上下两次GC情况,发现在FULL GC后垃圾有被回收,即EU和OU有变小,先排除内存泄漏。可以猜测应该是有大对象产生触发老年代空间担保机制,直接将老年代占满从而触发FULL GC。)

3、通过jmap -histo 18830| head -n 20 命令查看堆中比较多的对象

根据PaTerminalRealTimeQuery对象找到近期提交的代码,是漏掉一个设备id的参数,导致数据库中200w的设备数据都被捞到list中来。产生了大对象。

总结:主要是大对象的产生导致第一天的数据库连接被占用,第二天的内存过大、频繁FULL GC问题。

优化范式:

1、调整错误的业务代码

2、增加gc日志及dump文件的打印,具体参数改变如下
修改前:

-Xms5120M -Xmx5120M -Xmn1024M -XX:PermSize=256M -XX:MaxPermSize=512M -Xss256K -XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -XX:SoftRefLRUPolicyMSPerMB=0

修改后:

-Xms3072M -Xmx3072M -Xmn1024M -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=512M -Xss256K -XX:SurvivorRatio=1 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSClassUnloadingEnabled -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:+PrintGCDateStamps -XX:+PrintTenuringDistribution -verbose:gc -Xloggc:/tysl/log/gc/manageLoadBalance-gc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tysl/log/

修改点:

1、内存用不了这么大,反而老年代过大反而会让stw的时间边长,调小老年代内存

2、增加gc日志及dump的打印信息,以便后续排查问题

3、原项目估计是从1.7升级到1.8的,永久代的参数没有改过来,极端情况下,如遇到某些动态代理对象的生成会将元空间不断扩展(因为元空间不设置默认是共享整个物理内存空间的,极端场景会压缩堆空间,触发频繁FULL GC)-XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=512M

相关推荐
顺风尿一寸7 小时前
从 FileOutputStream 到 int fd:一次 JNI 字段读写全链路源码剖析
linux·jvm
用户094248568037 小时前
第36章:JVMTI、Java Agent与运行时扩展点
java·jvm
脚踏实地,坚持不懈!8 小时前
Linux 内存回收机制:水位线、kswapd 与 Direct Reclaim
linux·jvm·算法
wuminyu8 小时前
ZGC染色指针在虚拟线程stackChunkOop上的并发屏障全景分析
java·linux·c语言·jvm·c++
江湖有缘1 天前
Docker实战 | 使用Docker部署rmoments社交平台
jvm·docker·oracle
H.莓飛1 天前
【C++】内存管理
linux·开发语言·jvm·c++·visual studio
10mAh1 天前
【SQL】NOT IN 遇到 NULL 为什么返回空集?三值逻辑与反关联实战
jvm·数据库·sql
wuminyu1 天前
stackChunkOop内部结构与GC屏障的配合工作原理剖析
java·linux·c语言·jvm·c++
老三牛擦2 天前
订单履约流程
jvm
青春逝如流水2 天前
Java 线程在内存模型(JMM)与 JVM 实现:规范与落地的多元路径
java·开发语言·jvm·多线程·ai文章