关于一次程序应用,内存持续升高。排查以及解决方案。
一、背景:
发现该程序的内存持续增长,无法释放,直到程序关闭/重启后才能释放。否则内存越来越高导致程序处理越来越慢。
二、分析排查
要解决内存持续增长的问题,首先需要定位问题,才能做相应的修复。对于逻辑简单的代码,可以简单直接通过排除法来定位问题代码所在,对于错综复杂的代码,就需要耗费一定时间了。
当然除了排除法,还可以借助内存检测工具来快速定位问题代码。对于.net平台,微软提供.net辅助工具CLR Profiler帮助我们的性能测试人员以及研发人员,找到内存没有及时回收,占着内存不释放的方法。
监测客户端程序运行的结果如下:
这是事后在测试环境,空业务使用下,检测了一个晚上。发现内存使用率还是稳定上升,即使用GC强行回收也只能回收到300多。
看看检测到的内存溢出的分析报告。
经过注释代码方式测试,空业务测试。发现内存还是在涨,注释代码只是影响内存涨的速度
也通过注释代码查到是哪一块问题。发现是公司插件库里面一个插件,链路疯狂继承,反复实例。导致变成动态数组,donet无法对它进行回收:( 这个span串了很多个builder )
对话:
A: 难道这个还不能实锤吗
还有其他原因
我: ispan 里面还有问题
不全部是延时队列
其实就是ispan里面有问题,所以延时队列才会也有问题
不能认为以为是延时队列导致的
三、解决方案
1.项目中添加运行时配置文件(CG强制回收配置-临时解决方案):
runtimeconfig.template.json
{
"runtimeOptions": {
"configProperties": {
"System.GC.HeapHardLimit": 419430400,
"System.GC.Server": false,
"System.GC.Concurrent": false
}
}
}
2.运维配合写了一个脚本,获取内存占比到达80%,重启一下应用(临时解决方案):
#!/bin/bash
mydate=`date +%Y%m%d_%H%M%S`
myhomedir="/dydata/pro_deliveryFoodSendOrderTask"
mylogdir="${myhomedir}/logs"
ps axf -o "pid %cpu" | awk '{if($2>=80.0) print $1}' | while read procid
do
kill -9 $procid
sleep 10
[ ! -d $mylogdir ] && mkdir $mylogdir
cd ${myhomedir}
nohup dotnet ./FoodOrderTask.dll >>${mylogdir}/start_${mydate}.log 2>&1 &
done