● 公司核心系统内存泄露排查

查找内存泄露

之前写了个系统监控的程序,在某次升级一个项目后,每隔2个月左右会收到服务器的监控提醒,使用top命令查询发现一个核心asp.net core web api内存异常。

WX20220511-100051

api仅有两个功能,简单却很重要,主要负责承上启下:

  • redis subscribe/publish
  • 作为路由使用http(s)中转所有项目后端接口数据

每次在收到提醒邮件后,到服务器准备用dotnet-dump转储文件时,都会报错Writing dump failed (HRESULT: 0x80004005),估计是剩余内存不足以进行分析。

只能检查自己的代码,检查过2次代码都没查出问题。因为避开了HttpClient的坑,所以一直怀疑第三方redis库出的问题,但是api没有任何报错,有几次在api重启后几天一直观察,没有发现内存上升,一直无法定位bug具体在哪里。遇到这种提醒,只能重启进程先解决问题,防止系统宕机。

今天突然想起来距离上次报错已经1个月了。查了下服务器,api内存占用19%,已经比较高了。top命令获取到pid为10680,试了下dotnet-dump可以正常使用。

dotnet-dump collect -p 10680

Writing full to /root/core_20220511_092512
Complete

文件大小:1.8G 😳

分析核心转储

进入交互式shell开始分析文件内容:

dotnet-dump analyze core_20220511_092512

查看大于10M的对象信息,可以看到CSRedis占用了大量的内存:

dumpheap -stat -min 10240

WX20220511-093510

可以用 !gcroot 查看某一个object到底被谁持有:

gcroot -all xxxxx

WX20220511-094257

最后确认罪魁祸首就是第三方库CSRedis,nuget没有新版本。找到了项目的GitHub,发现项目已经在2021年停止维护,作者已经重写了一个新项目FreeRedis😕。不太想用FreeRedis试错,也不想看作者源码找bug了,估计也看不懂😵。

CSRedis的ConcurrentQueue不知道是不是使用后没释放,导致数据越来越多,今天先使用GC.Collect()垃圾回收机制试下,如果过段时间还出现内存泄露,就只能把CSRedis替换掉才能彻底解决。

-END-