内存泄漏调优案列

案列背景

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

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

压测工具tps表现和现象

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

 Tps火焰图如下:

排查过程

内存dump,Mat分析

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

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

源码追踪 

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

调用处:

 

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

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

额外发现 

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

此处会定期清理session对象。

跟踪整个调用栈:

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

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

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

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

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

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

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

SessionImpl是有哪里创建的

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

 

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

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

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

再次验证

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

总结

1 确定内存泄漏对象

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

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

猜你喜欢

转载自blog.csdn.net/qq_39203337/article/details/128664900