问题
测试环境一切正常,生产环境发布后项目使用内存逐渐增加直至溢出,溢出后项目挂了,守护进程自动重启了,如此反复。
思路
- 测试环境正常,线上环境异常说明很可能是数据量,并发量导致的内存溢出。
- 查看最新服务器内存的使用情况(Skywalking,zabbix等工具),查看内存是从什么日期开始异常的,根据这个日期查看这个日期最近上线的功能,检查相关功能的代码,检查是否存在死锁,非托管资源没释放,线程阻塞等问题。
- 使用内存诊断工具收集项目进程的内存信息。分析内存内容, 查看内存占用较大的对象,对象之间的关系,定位到代码中相应的位置,进行优化修改。
- 如果还是排查不出来,可以用内存诊断工具分别收集内存占用低时的内存信息,和内存占用高时的内存信息,然后比较哪些对象在内存较高时占用的比较多
诊断工具
安装dotnet下的三个诊断工具
- dotnet-counters
一个性能监视工具,用于临时运行状况监视和初级性能调查, 你可以通过命令查看和存储,当前程序的运行时信息,它可以收集 CPU,内存,GC,线程,异常 等信息 - dotnet-trace
一个跨平台的 .NET Core 工具,在不使用本机探查器的情况下启用正在运行的进程的 .NET Core 跟踪集合,它是围绕 .NET Core 运行时的跨平台 EventPipe 技术而构建的,在 Windows、Linux 或 macOS 上提供相同体验。 - dotnet-dump
是性能收集和分析实用工具,流程是先用 dotnet-dump collect 命令 收集当前程序的运行时信息,然后通过 dotnet-dump analyze 命令启动交互式 shell命令,来分析程序。
安装如下:
dotnet tool install --global dotnet-counters
dotnet tool install --global dotnet-trace
dotnet tool install --global dotnet-dump
常用指令:
dotnet-counters collect:定期收集所选计数器的值,并将它们导出为指定的文件格式以进行后续处理。
dotnet-counters list:显示按提供程序分组的计数器名称和说明的列表。
dotnet-counters monitor:实时监控程序的运行信息
dotnet-counters ps:显示可监视的 dotnet 进程的列表
dotnet-trace collect:实时获取信息,数据收集到trace.nettrace文件,可以用VS打开该文件
dotnet-trace convert:将 nettrace 跟踪转换为备用格式,以便用于备用跟踪分析工具。
dotnet-trace ps:显示可附加到的 dotnet 进程的列表
dotnet-trace list-profiles:列出预生成的跟踪配置文件,并描述每个配置文件中包含的提供程序和筛选器。
dotnet-dump collect:从进程捕获转储。
dotnet-dump analyze:启动交互式 shell 以了解转储。 shell 接受各种 SOS 命令。
过程
登上服务器执行top指令查看服务器当前的状态,如图,可以看到进程7619的项目CPU占用260.6%(多核),内存占用46.5%
运行指令dotnet-counters monitor -p 7619
可以看当前服务器的运行信息,如图可以看到GC0,1代的内存占用并不大,2代和LOH大对象堆占用了大量的内存。这时候就需要使用dump工具来分析是哪些对象占用了大量的内存。
执行指令dotnet-dump collect -p 7619
从进程捕获信息转储到文件。
执行指令dotnet-dump analyze core_20200910_142445
启动交互式shell开始分析文件内容
执行指令dumpheap -stat -min 10240
查看大于10M的对象信息,可以看到System.Byte[]和System.String占用了大量的内存。
执行指令dumpheap -mt 00007f15c4d914c0 -min 10240
查看System.Byte[]对应的对象,可以看到有14917个对象,每个对象都占了大概170000kb内存。我们取其中一个对象查看其内容。
执行指令dumpobj 00007f108e4f8ff8
,可以看到该对象的具体内容,根据内容信息定位到对应的代码。
基于以上分析结果,排查对应源代码就是问题的根源,对其优化解决问题。
官方文档:https://docs.microsoft.com/zh-cn/dotnet/core/diagnostics/debug-memory-leak