记录一次内存泄漏排查过程
某天收到運(yùn)維線上警報(bào),服務(wù)器內(nèi)存告警,需要處理一下。此時(shí)通過瀏覽器打開頁面,系統(tǒng)可以正常訪問,但是有明顯卡頓。為了不影響客戶使用,先重啟了服務(wù)釋放了內(nèi)存。由于該項(xiàng)目平時(shí)訪問量并不大,因此隨著程序運(yùn)行內(nèi)存占用率的增長比較緩慢,直到第三天才發(fā)現(xiàn)從原本的10%跳到了45%。初步懷疑有內(nèi)存泄漏問題需要進(jìn)行線上排查。
調(diào)試內(nèi)存泄漏教程 - .NET | Microsoft Learn
服務(wù)器環(huán)境
- Linux:CentOS Linux release 7.6.1810 (Core)
- .NET SDK:.NET SDK (5.0.408)
安裝診斷工具
在服務(wù)器上安裝dotnet tool下的診斷工具
-
dotnet-counters是一個(gè)性能監(jiān)視工具,用于臨時(shí)運(yùn)行狀況監(jiān)視和初級(jí)性能調(diào)查。 -
dotnet-dump是在未涉及任何本機(jī)調(diào)試器的情況下收集和分析 Windows、Linux 和 macOS 轉(zhuǎn)儲(chǔ)的方法。 可以運(yùn)行 SOS 命令來分析崩潰和垃圾回收器 (GC)
dotnet tool install -g dotnet-counters
dotnet tool install -g dotnet-dump
安裝過程中可能遇到的問題:
1. Https 訪問證書問題
NuGet.Protocol.Core.Types.FatalProtocolException: 無法加載源 https://api.nuget.org/v3/index.json 的服務(wù)索引。
---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception.
---> System.Security.Authentication.AuthenticationException: The remote certificate is invalid because of errors in the certificate chain: UntrustedRoot
執(zhí)行openssl version -a查找安裝目錄,然后執(zhí)行cp /etc/pki/tls/cert.pem /usr/local/openssl-1.1.1o/ssl/命令將默認(rèn)證書放到SSL目錄
2. dotnet tool 版本問題
Unable to find package dotnet-counters. No packages exist with this id in source(s): nuget.org
或
error NU1202: Package dotnet-counters 8.0.452401 is not compatible with net5.0 (.NETCoreApp,Version=v5.0) / any. Package dotnet-counters 8.0.452401 supports: net6.0 (.NETCoreApp,Version=v6.0)
根據(jù)服務(wù)器上的.NET SDK版本,指定版本號(hào)完成的安裝。版本號(hào):https://www.nuget.org/packages/dotnet-counters
分析過程
通過Top命令查看進(jìn)程資源占用情況,輸入M按內(nèi)存使用百分比排序,并獲取到程序PID。
運(yùn)行dotnet-counters monitor -p 6309,查看程序運(yùn)行信息,發(fā)現(xiàn)Gen 2和LOH占用大量內(nèi)存。
關(guān)于GC相關(guān)內(nèi)容可以看官方文檔ASP.NET Core 中的內(nèi)存管理和模式
(上面兩張截圖是事后截取的,作演示用)
運(yùn)行dotnet-dump collect -p 6309,在當(dāng)前目錄生成程序內(nèi)存dump文件
運(yùn)行dotnet-dump analyze core_20231026_162034分析dump文件,進(jìn)入交互式shell,通過SOS命令分析文件內(nèi)容。相關(guān)SOS命令可以查看官方文檔dotnet-dump 診斷工具
運(yùn)行dumpheap -stat -min 85000,查看大于85000 B的對(duì)象,可以看到有78個(gè)大System.Byte[]類型的對(duì)象。
運(yùn)行dumpheap -mt -min 85000查看具體的大對(duì)象列表。GC 會(huì)為大型對(duì)象(大于 85,000 字節(jié))創(chuàng)建特殊內(nèi)存區(qū)域,稱為大型對(duì)象堆 (LOH)。
運(yùn)行dumpobj 00007fdfbd54ead0,查看對(duì)象內(nèi)容。
比對(duì)下各個(gè)對(duì)象內(nèi)容,大部分為亂碼,少數(shù)顯示Exif和JFIF等字符。聯(lián)想到最近項(xiàng)目更新中包含了一部分圖片處理相關(guān)功能,因此初步懷疑是ImageResize的代碼有問題,導(dǎo)致了內(nèi)存泄漏。
運(yùn)行gcroot 00007f8c51457968,查看對(duì)象引用情況,沒有任何對(duì)象引用。
重寫修改了代碼后上線,隨著相關(guān)接口被調(diào)用,程序的內(nèi)存占用依舊會(huì)上漲。通過dotnet-counters查看發(fā)現(xiàn)Gen2和LOH占用大量內(nèi)存沒有被回收。
查閱官方文檔的過程中發(fā)現(xiàn),臨時(shí)大對(duì)象會(huì)導(dǎo)致第 2 代 GC,但是不理解為什么這些內(nèi)存沒有被回收。
解決方案
2023-10-27 更新:原本項(xiàng)目中使用System.Drawing對(duì)圖片進(jìn)行壓縮處理,綜合考慮后選擇使用SixLabors.ImageSharp重寫這部分代碼。目前更新在線上觀察一段時(shí)間。
總結(jié)
以上是生活随笔為你收集整理的记录一次内存泄漏排查过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 自定义xunit测试用例的执行顺序
- 下一篇: .net core 到底行不行!超高稳定