记录一次内存泄漏排查过程
某天收到運維線上警報,服務器內存告警,需要處理一下。此時通過瀏覽器打開頁面,系統可以正常訪問,但是有明顯卡頓。為了不影響客戶使用,先重啟了服務釋放了內存。由于該項目平時訪問量并不大,因此隨著程序運行內存占用率的增長比較緩慢,直到第三天才發現從原本的10%跳到了45%。初步懷疑有內存泄漏問題需要進行線上排查。
調試內存泄漏教程 - .NET | Microsoft Learn
服務器環境
- Linux:CentOS Linux release 7.6.1810 (Core)
- .NET SDK:.NET SDK (5.0.408)
安裝診斷工具
在服務器上安裝dotnet tool下的診斷工具
-
dotnet-counters是一個性能監視工具,用于臨時運行狀況監視和初級性能調查。 -
dotnet-dump是在未涉及任何本機調試器的情況下收集和分析 Windows、Linux 和 macOS 轉儲的方法。 可以運行 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 的服務索引。
---> 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
執行openssl version -a查找安裝目錄,然后執行cp /etc/pki/tls/cert.pem /usr/local/openssl-1.1.1o/ssl/命令將默認證書放到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)
根據服務器上的.NET SDK版本,指定版本號完成的安裝。版本號:https://www.nuget.org/packages/dotnet-counters
分析過程
通過Top命令查看進程資源占用情況,輸入M按內存使用百分比排序,并獲取到程序PID。
運行dotnet-counters monitor -p 6309,查看程序運行信息,發現Gen 2和LOH占用大量內存。
關于GC相關內容可以看官方文檔ASP.NET Core 中的內存管理和模式
(上面兩張截圖是事后截取的,作演示用)
運行dotnet-dump collect -p 6309,在當前目錄生成程序內存dump文件
運行dotnet-dump analyze core_20231026_162034分析dump文件,進入交互式shell,通過SOS命令分析文件內容。相關SOS命令可以查看官方文檔dotnet-dump 診斷工具
運行dumpheap -stat -min 85000,查看大于85000 B的對象,可以看到有78個大System.Byte[]類型的對象。
運行dumpheap -mt -min 85000查看具體的大對象列表。GC 會為大型對象(大于 85,000 字節)創建特殊內存區域,稱為大型對象堆 (LOH)。
運行dumpobj 00007fdfbd54ead0,查看對象內容。
比對下各個對象內容,大部分為亂碼,少數顯示Exif和JFIF等字符。聯想到最近項目更新中包含了一部分圖片處理相關功能,因此初步懷疑是ImageResize的代碼有問題,導致了內存泄漏。
運行gcroot 00007f8c51457968,查看對象引用情況,沒有任何對象引用。
重寫修改了代碼后上線,隨著相關接口被調用,程序的內存占用依舊會上漲。通過dotnet-counters查看發現Gen2和LOH占用大量內存沒有被回收。
查閱官方文檔的過程中發現,臨時大對象會導致第 2 代 GC,但是不理解為什么這些內存沒有被回收。
解決方案
2023-10-27 更新:原本項目中使用System.Drawing對圖片進行壓縮處理,綜合考慮后選擇使用SixLabors.ImageSharp重寫這部分代碼。目前更新在線上觀察一段時間。
總結
以上是生活随笔為你收集整理的记录一次内存泄漏排查过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 自定义xunit测试用例的执行顺序
- 下一篇: .net core 到底行不行!超高稳定