記一次 .NET 某電廠Web系統 內存泄漏分析

一:背景

1. 講故事

前段時間有位朋友找到我,說他的程序內存占用比較大,尋求如何解決,截圖就不發了,分析下來我感覺除了程序本身的問題之外,.NET5 在內存管理方面做的也不夠好,所以有必要給大家分享一下。

二:WinDbg 分析

1. 托管還是非托管泄漏

這個還是老規矩 !address -summary!eeheap -gc 組合命令排查一下。

0:000>?!address?-summaryMapping?file?section?regions...
Mapping?module?regions...
Mapping?PEB?regions...
Mapping?TEB?and?stack?regions...
Mapping?heap?regions...
Mapping?page?heap?regions...
Mapping?other?regions...
Mapping?stack?trace?database?regions...
Mapping?activation?context?regions...
---?State?Summary?----------------?RgnCount?-----------?Total?Size?--------?%ofBusy?%ofTotal
MEM_FREE????????????????????????????????426?????7df8`af1ce000?(?125.971?TB)???????????98.42%
MEM_RESERVE?????????????????????????????619??????206`01b9c000?(???2.023?TB)??99.75%????1.58%
MEM_COMMIT?????????????????????????????3096????????1`4f286000?(???5.237?GB)???0.25%????0.00%0:000>?!eeheap?-gc
Number?of?GC?Heaps:?16
------------------------------
...
Heap?15?(0000024AF6BAA2E0)
generation?0?starts?at?0x000002509729B538
generation?1?starts?at?0x000002509720B638
generation?2?starts?at?0x0000025096F91000
ephemeral?segment?allocation?context:?nonesegment?????????????begin?????????allocated?????????committed????allocated?size????committed?size
0000025096F90000??0000025096F91000??000002509B5AFB40??000002509DFE9000??0x461eb40(73526080)??0x7058000(117800960)
Large?object?heap?starts?at?0x00000250D6F91000segment?????????????begin?????????allocated?????????committed????allocated?size????committed?size
00000250D6F90000??00000250D6F91000??00000250DEB6AC60??00000250DEB6B000??0x7bd9c60(129866848)??0x7bda000(129867776)
Pinned?object?heap?starts?at?0x00000250E6F91000
00000250E6F90000??00000250E6F91000??00000250E75D94E0??00000250E75DA000??0x6484e0(6587616)??0x649000(6590464)
Allocated?Heap?Size:???????Size:?0xc840c80?(209980544)?bytes.
Committed?Heap?Size:???????Size:?0xec32000?(247668736)?bytes.
------------------------------
GC?Allocated?Heap?Size:????Size:?0xd6904dd8?(3599781336)?bytes.
GC?Committed?Heap?Size:????Size:?0x11884b000?(4706316288)?bytes.

從卦中指標看:5.2G4.7G ,很明顯問題出在了托管層,但如果你細心的話,你會發現這 4.7G 是 commit 內存,其實真正占用的只有 3.5G,言外之意有 1.2G 的空間其實屬于 Commit 區,也就是為了少向 OS 申請內存而虛占的一部分空間,畫個簡圖就像下面這樣:

95ae70f9ac55d4ba8860cd8a8cf68890.png

這也是我第一次看到 AllocCommit 差距有這么大。

2. 探究托管內存占用

首先看下 3.5G 內存這塊,這個分析比較簡單,直接看托管堆就好了。

0:000>?!dumpheap?-stat
Statistics:MT????Count????TotalSize?Class?Name
...
00007ffa19e64808????25804?????36125600?xxxx.MongoDB.Entity.GeneratorMongodb
0000024af68aa2c0????20517????630474976??????Free
00007ffa1947bf30????52477????654558722?System.Byte[]
00007ffa194847f0?????1921???1044818774?System.Char[]
00007ffa19437a90???673850???1116597742?System.String

從輸出信息看,主要還是被 String,Char[],Byte[] 占用了,根據經驗,這三個組合在一塊,大多是存了什么字節流在內存中,比如 PdfImage ,然后在內存中倒來倒去就成這個樣子了。

接下來在 char[] 中抽一些 obj 看一下,果然大多是 jpg

0:000>?!DumpObj?/d?00000250da9d3618
Name:????????System.Char[]
MethodTable:?00007ffa194847f0
EEClass:?????00007ffa19484770
Size:????????11990052(0xb6f424)?bytes
Array:???????Rank?1,?Number?of?elements?5995014,?Type?Char?(Print?Array)
Content:?????data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAA4QAAASwCAYAAACjAoQOAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DA
Fields:
None
0:000>?!DumpObj?/d?00000250db542a60
Name:????????System.Char[]
MethodTable:?00007ffa194847f0
EEClass:?????00007ffa19484770
Size:????????15667860(0xef1294)?bytes
Array:???????Rank?1,?Number?of?elements?7833918,?Type?Char?(Print?Array)
Content:?????data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAA4QAAASwCAYAAACjAoQOAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DA
Fields:
None

可以看到,3.2G 的內存大多是被 圖片 所占用,朋友反饋是把 圖片 存到數據庫所致,好了,這一塊就分析到這里,分析思路也很明顯,接下來探究下 alloc 和 commit 的問題。

3. 為什么 alloc 和 commit 差距這么大

一般而言,差距大有以下幾點誘因所致。

  1. segment 越大,commit 預設的區域就越大

根據官方文檔的定義,segment 的大小取決于 cpu核數 和 程序的位數,截圖如下:

cda554219c53ed4bbebce24d9dd62fb3.png

有了這個指標,怎么到 dump去找各自數據呢,用 !eeversion 看下 heap 的個數以及觀察下內存地址的長度就好啦。

0:000>?!eeversion
5.0.621.22011?free
5,0,621,22011?@Commit:?478b2f8c0e480665f6c52c95cd57830784dc9560
Server?mode?with?16?gc?heaps
SOS?Version:?6.0.5.7301?retail?build

可以看到,這個程序是用 64bit 跑在 16 核機器上,segment 上限為 1G

  1. segment 越多,alloc 和 commit 累計差距就會越大

每個 segment 都差一點,那多個 segment 自然就累計出來了,接下來就找一下那些差距比較大的 segment。

Heap?0?(0000024AF685A500)segment?????????????begin?????????allocated?????????committed????allocated?size????committed?size
0000024AF6F90000??0000024AF6F91000??0000024AF83B6D28??0000024AFEB42000??0x1425d28(21126440)??0x7bb1000(129699840)
------------------------------
Heap?1?(0000024AF68819A0)segment?????????????begin?????????allocated?????????committed????allocated?size????committed?size
0000024B56F90000??0000024B56F91000??0000024B58507410??0000024B5D2E5000??0x1576410(22504464)??0x6354000(104153088)
------------------------------
Heap?4?(0000024AF688F770)segment?????????????begin?????????allocated?????????committed????allocated?size????committed?size
0000024C76F90000??0000024C76F91000??0000024C783BDBE8??0000024C7ECF7000??0x142cbe8(21154792)??0x7d66000(131489792)
------------------------------
Heap?6?(0000024AF68980A0)segment?????????????begin?????????allocated?????????committed????allocated?size????committed?size
0000024D36F90000??0000024D36F91000??0000024D38B87E78??0000024D3F881000??0x1bf6e78(29322872)??0x88f0000(143589376)
...

從輸出信息看,差距最大的是 Heap6,高達 110M,那這 110M 差距是否合理呢?其實仔細想想也不太離譜,畢竟命中了上面提到的兩點,但我覺得這里的空間是不是還可以再智能的優化一下,再縮小一點?

4. Commit區能不能再小點?

能不能縮的再小一點,其實這是一種 CLR 智能算法的抉擇,Commit 區越大,申請對象的速度就越快,向 OS 申請內存的頻率就越低,反之 Commit 區越小,向 OS 再次申請內存的概率就越大,段的模型圖大概是這個樣子:

c749266f0dfbc5c4ad229f32cf130cba.png

后來仔細想了下,既然 Commit 區多保留了 110M,那曾經肯定是某一個時刻突破過,后來因為成了垃圾對象,被 GC 回收了,但內存區域被GC私藏下來,所以程序肯定出現過 快出快進 的現象,接下來的想法就是用 writemem 把 alloc ~ commit 的內存區間給導出來看下,是不是有什么新發現。

0:000>?.writemem?D:\dumps\dump1\1.txt?0000024AF83B6D28?L?0x0678b2d8?
Writing?678b2d8?bytes.............
513ba2fdf41492a7fc6f1c369060a929.png

發現了很多類似這樣的信息,把這個信息提供給朋友后,朋友說他找到這塊問題了,是網站上用 NPOI ?數據導出 功能所致。

三:總結

其實這個 dump 給了我們兩方面的教訓。

  1. 不要將 image 放到 sqlserver 里,不僅占用sql的資源,讓程序也不堪重負,畢竟讀出去都是 byte[] ...

  2. coreclr 雖然有自己的抉擇算法,如果再智能一點就好了,讓 commit ~ alloc 之間的差距更合理一點。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/284844.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/284844.shtml
英文地址,請注明出處:http://en.pswp.cn/news/284844.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Bomb(hdu 3555)

題意&#xff1a;給定一個閉區間&#xff0c;求區間內有多少數中含“49” /*dp[i][j]表示i位數以j為最高位位中的所有不符合數的個數。然后把數字拆分&#xff0c;亂搞即可。 */ #include<cstdio> #include<iostream> #define lon long long using namespace std; …

《深入實踐Spring Boot》下載

本書以豐富的實例&#xff0c;介紹了如何使用SpringBoot開發框架進行基礎應用和分布式應用等方面的開發&#xff0c;以及如何使用SpringBoot開發的應用構建高性能的服務平臺&#xff0c;同時還對SpringBoot的一些核心代碼進行了深入剖析。本書從基本的入門&#xff0c;到數據庫…

【ArcGIS微課1000例】0021:ArcToolBox工具箱功能與環境概述

文章目錄 一、ArcToolBox功能簡介1. 3D分析工具2. 分析工具3. 制圖工具4. 轉換工具5. 數據管理工具6. 地理編碼工具7. 地統計分析工具8. 線性參考工具9. 空間分析工具10. 空間統計工具二、ArcToolBox環境設置一、ArcToolBox功能簡介 ArcToolbox的空間處理工具條目眾多、功能豐…

[轉]將圖片轉換為 latex 公式

一、官網鏈接及使用方法 官網鏈接&#xff08;跨平臺&#xff09;: Mathpix 公式截圖快捷鍵截圖生成 latex 公式--------------------- 作者&#xff1a;man_world 來源&#xff1a;CSDN 原文&#xff1a;https://blog.csdn.net/mzpmzk/article/details/84140617 版權聲明&…

在SQL Server2005中使用 .NET程序集

昨天完成了一個最簡單的在數據庫中創建標量值函數,今天主要完成表值函數,存儲過程和用戶定義類型在和.NET結合下的使用方法.1,表值函數所謂表值函數就是說這個函數返回的結果是一個Table,而不是單個的值.在.NET 中創建這樣的函數,返回的結果是一個IEnumerable接口.這個接口非常…

C# 實例解釋面向對象編程中的接口隔離原則

在面向對象編程中&#xff0c;SOLID 是五個設計原則的首字母縮寫&#xff0c;旨在使軟件設計更易于理解、靈活和可維護。這些原則是由美國軟件工程師和講師羅伯特C馬丁(Robert Cecil Martin)提出的許多原則的子集&#xff0c;在他2000年的論文《設計原則與設計模式》中首次提出…

Appium同時運行多個設備

為了提高測試效率&#xff0c;測試需要同時在多個android設備上運行&#xff0c;就需要啟動多個appium。 啟動appium時&#xff0c;為每個設備設置不同的端口號&#xff0c;并為driver設置該設備的udid。見如下實例&#xff0c;關鍵是紅色部分 DesiredCapabilities capabilitie…

AI作畫的業界天花板被我找到了,AIGC模型揭秘 | 昆侖萬維

一、前景 1、AI和AIGC的關系 人工智能&#xff08;Artificial Intelligence&#xff09;&#xff0c;英文縮寫為AI。它是研究、開發用于模擬、延伸和擴展人的智能的理論、方法、技術及應用系統的一門新的技術科學。 AIGC是繼 UGC、PGC 之后新型利用AI技術自動生成內容的生產…

【ArcGIS微課1000例】0022:ArcGIS點(點坐標)自動連成線操作案例教程

ArcGIS中,可以將帶三維坐標(X、Y、Z)的點/點集自動連成線,本文演示具體操作流程。 文章目錄 實戰演練GPS點數據下載實戰演練 打開ArcMap軟件,添加實驗文件夾0022下的GPS軌跡點.shp矢量點數據(文末提供下載地址),該數據是由GPS RTK采集的河道點數據,首先需要將GPS點坐…

微信公眾號 文章的爬蟲系統

差不多倆個星期了吧&#xff0c;一直在調試關于微信公眾號的文章爬蟲系統&#xff0c;終于一切都好了&#xff0c;但是在這期間碰到了很多問題&#xff0c;今天就來回顧一下&#xff0c;總結一下&#xff0c;希望有用到的小伙伴可以學習學習。 1、做了倆次爬蟲了&#xff0c;第…

[轉]關于C#操作WPS和office兼容性的問題

最近一直在做的開發是關于導出word的功能&#xff0c;一開始的做法是在VS中直接添加引用office PIA&#xff0c;Microsoft.Office.Interop.Word&#xff0c;VS08有兩個版本&#xff0c;V11和V12&#xff0c;V11對應的是office03&#xff0c;V12對應的office07&#xff0c;試驗之…

AI入門到進階到放棄

前些天&#xff0c;發現了一個比較好的AI學習網站&#xff0c;有很多數學基礎&#xff0c;也通俗易懂&#xff0c;我自己先記錄起來防止忘記&#xff0c;猛戳這里&#xff08;學習網站&#xff09;

OAuth認證與授權

什么是OAuth授權&#xff1f; 一、什么是OAuth協議OAuth(開放授權)是一個開放標準。允許第三方網站在用戶授權的前提下訪問在用戶在服務商那里存儲的各種信息。而這種授權無需將用戶提供用戶名和密碼提供給該第三方網站。OAuth允許用戶提供一個令牌給第三方網站&#xff0c;一個…

IO的多路復用

一、概念: 使單線程或者單進程同時監測若干個文件描述符具有執行的能力&#xff1b; 二、作用: 類似于多進程和多線程 三、必要性: 多線程或者多進程對資源需求較高 四、IO模型: 1.阻塞io 不設置的話系統默認 2.非阻塞io 在阻塞io的基礎上調整為不在阻塞狀態 用到的函數接口…

C# 禁用 全局快捷鍵

本文經原作者授權以原創方式二次分享&#xff0c;歡迎轉載、分享。原文作者&#xff1a;唐宋元明清原文地址&#xff1a;https://www.cnblogs.com/kybs0/p/12558056.htmlC# 禁用 全局快捷鍵給軟件添加快捷鍵時&#xff0c;經常遇到其它軟件或者系統已設置的快捷鍵&#xff0c;導…

SegmentFault Hackathon 文藝復興

我有一個 idea&#xff0c;我想實現它&#xff0c;我正實現它&#xff0c;我已實現它。世界上存在一些好奇心旺盛、不愛墨守成規的人&#xff0c;略微偏執但又極度投入的他們崇尚自由&#xff0c;熱衷用技術實現自己的想法&#xff0c;他們帶著不羈的態度生活&#xff0c;利用編…

臥槽!VS Code 上竟然也能畫流程圖了???

作為一款開源的主流代碼編輯器&#xff0c;VSCode 在發布之后一直受到不少開發者的喜愛。 此前&#xff0c;我們也曾在公眾號上分享過多篇文章&#xff0c;向大家推薦了不少 VSCode 上比較實用&#xff08;或沙雕&#xff09;的插件。因此&#xff0c;有很多水友也經常調侃道&…

【QGIS入門實戰精品教程】14.1:QGIS如何加載各種在線地圖?

文章目錄 一、XYZ Tiles連接方式二、插件添加三、WMS/WMTS/OWS連接方式一、XYZ Tiles連接方式 1. 加載OpenStreetMap QGIS默認可以加載OpenStreetMap地圖。在左側點擊XYZ Tiles,默認下面有個OpenStreetMap選項,雙擊打右側會顯示地圖,如下圖所示: 在OpenStreetMap上右鍵→…

Oracle11g不能導出空表問題

ORACLE 11g 用exp命令導出庫文件備份時&#xff0c;發現只能導出來一部分表而且不提示錯誤&#xff0c;之前找不到解決方案只能把沒導出來的表重新建建立。后來發現是所有的空表都沒有導出來。于是想好好查查,因為在以前的10g版本中沒有這樣的問題。查資料發現Oracle 11g中有個…

SkiaSharp 之 WPF 自繪時鐘(案例版)

SkiaSharp是一個跨平臺2D圖形API&#xff0c;用于.NET平臺&#xff0c;基于Googles Skia Graphics庫(skia.org網站). 它提供了一個全面的2D API&#xff0c;可以跨移動、服務器和桌面模型來渲染圖像。該圖形庫可實現獲取指定坐標像素值、繪制2d圖形、繪制文字&#xff08;必須有…