問題
測試環境一切正常,生產環境發布后項目使用內存逐漸增加直至溢出,溢出后項目掛了,守護進程自動重啟了,如此反復。
思路
- 測試環境正常,線上環境異常說明很可能是數據量,並發量導致的內存溢出。
- 查看最新服務器內存的使用情況(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