背景
最近我们的项目出现了内存激增的情况,初次探讨,我们发现和机器人发生通信之后,内存会缓慢上升,直到系统崩溃。
例子
由于只是介绍一个简单的方案,所以就写一个比较简单的例子来演示了,代码如下:
internal class Program
{static void Main(string[] args){Dictionary<int, List<int>> dict = new Dictionary<int, List<int>>();for(int i = 0; i < 100000000; i++){dict[i]=new List<int>();for(int j = 0; j < 100000000; j++){dict[i].Add(j);}Console.WriteLine($"dict[{i}].Count={dict[i].Count}");}Console.WriteLine($"dict.Count={dict.Count}");}
}
不难看出,这是一个故意写成内存泄漏的例子,其中创建一个字典dict,键为整数,值也为整数,不断创建对象放入字典中,内存会不断增长,最终崩溃。
调试
1.打开vs2022,把项目的启动方式改为Release
2.选择“调试->性能探测器”
3.勾选内存使用率项,然后开始检测
4.检测的过程中,我们可以对当前内存中各对象的占用情况进行多次抓拍
5.抓拍了差不多的时候,就可以停止收集,开始分析
6.如上,我们选择最后一个抓拍的结果,点击查看堆
7.东西有点多,是不是看不懂,没关系,选择显示死对象,因为内存泄漏很多情况都是因为死对象没得到释放造成的。
8.还是太多,不过已经能看出是一个Int32数组的问题,我们还可以继续过滤其他的,选择代码中的大型对象。
9.点击最终锁定的Int32[],会看到其调用情况
10. C#中List底层就是一个数组来维护的,点击List<int>继续展开
可以看到,已经精准定位到字典的问题,因为代码是我们写的,这个字典在哪里进行调用,我们自己很清楚,于是就有了排查的方向。