内存泄漏调优案列

案列背景

最近在做公司项目核心接口压测和稳定性压测时,各接口的成功率不足99.99%,通过分割压测之后发现,在压测A服务时,内存上升明显,且伴有频繁的fgc发生

内存泄漏调优案列_第1张图片

 jvm老年代内存使用率已经达到了100%且应用的fgc有5000+次,fgc频率大概在2s左右,怀疑有内存泄漏问题产生

压测工具tps表现和现象

内存飙升导致频繁的fgc,导致在压测时出现tps不稳定现象,出现毛刺现象

内存泄漏调优案列_第2张图片

 Tps火焰图如下:

内存泄漏调优案列_第3张图片

 

排查过程

内存dump,Mat分析

出现内存100%之后,将A服务的内存dump文件拿到之后,使用MAT工具分析,mat显示如下:

内存泄漏调优案列_第4张图片

从MAT工具上显示,有大量的SessionImpl对象存在,怀疑内存泄漏发生在此处

源码追踪 

通过跟踪源码,找到了InMemorySessionManager相关代码,并跟踪到了SessionImpl实例类代码如下:

内存泄漏调优案列_第5张图片

调用处:

内存泄漏调优案列_第6张图片 

在哪里调用了InMemorySessionmanager#createSession方法? 

内存泄漏调优案列_第7张图片

此时发现有多出地方会调用该方法,无法确定是由哪里导致Session创建的

额外发现 

通过使用jstat -gcutil 1 1000观察A服务的pod内存和gc情况,当压测一段时间之后停止压测,观察一段时间,发现pod的内存会逐步往下掉,最终内存会回退到正常范围,怀疑有SessionImpl过期清除机制。同时,在以上InMemorySessionManager代码中发现了如下方法:

内存泄漏调优案列_第8张图片

 

此处会定期清理session对象。

跟踪整个调用栈:

SessionImpl#maxInactiveInterval--->InMemorySessionManager#defaultSessionTimeout=30*60

InMemorySessionManager提供了方法setDefaultSessionTimeout方法可以修改此处属性

在UndertowServletWebServerFactory中有关于session的超时设置

内存泄漏调优案列_第9张图片

 为此,查询springboot自动装配关于session过期的设置:

内存泄漏调优案列_第10张图片

为了验证是否是由于该处设置引起的,增加关于session过期的设置,并且设置过期时间10s,再次压测:

此时,内存的上升速度没变,但是每次经过fgc

(cms垃圾收集器-XX:CMSInitiatingOccupancyFraction=70),内存回退到正常状态

SessionImpl是有哪里创建的

通过对比不同的服务之前的内存增长差异情况,发现之后A会出现如上内存快速增长情况。再结合session过期设置的验证效果,查询了A的业务代码发现如下代码:

内存泄漏调优案列_第11张图片

内存泄漏调优案列_第12张图片 

其中@ModelAttribute注解使用在方法上时,会在每次调用Control的方法前都会调用,注意到:

this.session = request.getSession();跟踪代码,发现最终会调用到InMemorySessionManager#getSession方法创建大量的SessionImpl存入到Sessions(一个ConcurrentHashMap)

至此,内存泄漏的最终元凶找到了

 

再次验证

 在A服务中,去掉对BaseController的继承,再次压测心跳接口,此时应用内存和gc恢复正常

总结

1 确定内存泄漏对象

出现内存泄漏问题,首先获取服务内存映射(当让也可以使用:(jmap  -histo:live   1 |head -20查看内存大对象),然后查看内存类。

2 分析代码,查询资料,确定泄漏来源

你可能感兴趣的:(jvm)