日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

记一次 .NET医疗布草API程序 内存暴涨分析

發布時間:2023/12/4 asp.net 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 记一次 .NET医疗布草API程序 内存暴涨分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一:背景

1. 講故事

我在年前寫過一篇關于CPU爆高的分析文章 再記一次 應用服務器 CPU 暴高事故分析 ,當時是給同濟做項目升級,看過那篇文章的朋友應該知道,最后的結論是運維人員錯誤的將 IIS 應用程序池設成 32bit 導致了事故的發生,這篇算是后續????????????,拖了好久才續上哈。

猶記得那些天老板天天找我們幾個人開會,大概老板是在傳導甲方給過來的壓力,人倒霉就是這樣,你說 CPU 爆高可怕吧,我硬是給摁下去了,好了,Memory 又爆高了,尼瑪我又給摁下去了,接著數據庫死鎖又來了,你能體會到這種壓力嗎????? 就像我在朋友圈發的那樣,程序再不跑我就要跑了。

所以有時候敬敬風水還是很有必要的,有點扯遠了哈,這篇我們來看看程序的內存暴漲如何去排查,為了讓你更有興趣,來一張運維發的內存監控圖。

從圖中可以看出,9點開始內存直線暴漲,絕對驚心動魄,要是我的小諾安這樣暴漲就好了????????????,接下來 windbg 說話。

二:windbg 分析

1. 說一下思路

內存暴漲了,最怕的就是 非托管層 出了問題,它的排查難度相比 托管層 要難10倍以上,所以遇到這類問題,先祈禱一下吧,gc堆也罷,loader堆也不怕,所以先看看是否 進程內存 ≈ gc堆內存 ?

2. 排查托管還是非托管

排查方式也很簡單,通過 !address -summary 看看進程的已提交內存,如下輸出:

0:000>?!address?-summary---?State?Summary?----------------?RgnCount?-----------?Total?Size?--------?%ofBusy?%ofTotal MEM_FREE????????????????????????????????261??????7fb`4b151000?(???7.982?TB)???????????99.77% MEM_RESERVE?????????????????????????????278????????2`6aafc000?(???9.667?GB)??51.35%????0.12% MEM_COMMIT?????????????????????????????2199????????2`4a3a3000?(???9.160?GB)??48.65%????0.11%

可以看到已提交內存是 9.1G,接下來看下 gc 堆的大小,使用 !eeheap -gc 即可。

0:000>?!eeheap?-gc Number?of?GC?Heaps:?8 ------------------------------ Heap?0?(0000000002607740) generation?0?starts?at?0x00000001aaaa5500 generation?1?starts?at?0x00000001aa3fd070 generation?2?starts?at?0x0000000180021000 Heap?7?(0000000002713b40) generation?0?starts?at?0x000000053b3a2c28 generation?1?starts?at?0x000000053a3fa770 generation?2?starts?at?0x0000000500021000------------------------------ GC?Heap?Size:????????????Size:?0x1fdfe58c8?(8556271816)?bytes.

從最后一行輸出中可以看到當前的占用是 8556271816 / 1024 /1024 /1024 = 7.9G ,太幸運了,果然是托管層出了問題,gc 上有大塊臟東西,這下有救了 ????????????。

3. 查看托管堆

知道托管堆出了問題后,接下來就可以用 !dumpheap -stat 去gc堆上翻一翻。

0:000>?!dumpheap?-stat Statistics:MT????Count????TotalSize?Class?Name 000007fef7b5c308????32867???????788808?System.DateTime 000007fef7b5e598????33049???????793176?System.Boolean 000007feec7301f8????30430??????1217200?System.Web.HttpResponseUnmanagedBufferElement 000007fef7b56020?????2931??????3130928?System.Object[] 000007fef7b580f8???219398??????5265552?System.Int32 000007fe9a0c5428????46423??????7799064?xxx.Laundry.Entities.V_InvoiceInfo 000007fef7b59638???164418??????7892064?System.Text.StringBuilder 000007fef7b56980???164713?????10059852?System.Char[] 000007fef7b5a278?????7351?????26037217?System.Byte[] 000007fe9a0d8758???????35?????28326856?xxx.Laundry.Entities.V_ClothesTagInfo[] 0000000002536f50????76837?????77016088??????Free 000007fe9a327ab0????46534????312964608?xxx.Laundry.Entities.V_InvoiceClothesInfo[] 000007fe9a0c4868??2068912????397231104?xxx.Laundry.Entities.V_ClothesTagInfo 000007fef7b55b70?98986851???3483764540?System.String 000007fe9a10ef80?23998759???3839801440?xxx.Laundry.Entities.V_InvoiceClothesInfo Total?126039641?objects

我去,托管堆上的 xxx.Laundry.Entities.V_InvoiceClothesInfo 對象居然高達 2399w ,占了大概 3.6G,這還不算其附屬對象,對了,如果直接用 !dumpheap -mt xxx 輸出 address 的話,很難進行UI中止,所以這里有一個小技巧,用 range 來限定一下,如下代碼所示:

0:000>?!dumpheap?-mt?000007fe9a10ef80?0?0000000180027b30Address???????????????MT?????Size 0000000180027800?000007fe9a10ef80??????160????? 0000000180027910?000007fe9a10ef80??????160????? 0000000180027a20?000007fe9a10ef80??????160????? 0000000180027b30?000007fe9a10ef80??????160?????Statistics:MT????Count????TotalSize?Class?Name 000007fe9a10ef80????????4??????????640?xxx.Laundry.Entities.V_InvoiceClothesInfo Total?4?objects

4. 查找引用根

接下來用 !gcroot 隨便找一個 address 查看它的引用鏈,看看它到底被誰引用著?

0:000>?!gcroot?0000000180027800 HandleTable:00000000013715e8?(pinned?handle)->?000000058003c038?System.Object[]->?00000004800238a0?System.Collections.Generic.List`1[[xxx.Laundry.APIService.Models.Common.BaseModel,?xxx.Laundry.APIService]]->?0000000317e01ae0?xxx.Laundry.APIService.Models.Common.BaseModel[]->?000000028010caf0?xxx.Laundry.APIService.Models.Common.BaseModel->?00000003014cbbd0?System.Collections.Generic.List`1[[xxx.Laundry.Entities.V_InvoiceInfo,?xxx.Laundry.Entities]]->?00000003014f3580?xxx.Laundry.Entities.V_InvoiceInfo[]->?00000003014cd7f0?xxx.Laundry.Entities.V_InvoiceInfo->?000000038cc49bf0?System.Collections.Generic.List`1[[xxx.Laundry.Entities.V_InvoiceClothesInfo,?xxx.Laundry.Entities]]->?000000038cc49c18?xxx.Laundry.Entities.V_InvoiceClothesInfo[]->?0000000180027800?xxx.Laundry.Entities.V_InvoiceClothesInfoFound?1?unique?roots?(run?'!GCRoot?-all'?to?see?all?roots).

從輸出中可以看到,它貌似被一個 List<BaseModel> 所持有,哈哈,總算找到了,接下來就簡單了,直接用 !objsize 看一看它的 size 有多大?

0:000>?!objsize?00000004800238a0 sizeof(00000004800238a0)?=?-1972395312?(0x8a6fa2d0)?bytes?(System.Collections.Generic.List`1[[xxx.Laundry.APIService.Models.Common.BaseModel,?xxx.Laundry.APIService]])

看到上面的 -1972395312 了嗎?我去,int 類型的 size 直接給爆掉了,果然是個大對象,就是你了。。。如果非要看大小也可以,寫一個腳本遍歷一下。

三:總結

知道是 List<BaseModel> 做的孽后,仔細閱讀了源碼才知道,原來是給用戶第一次數據全量同步的時候,服務端為了加速將數據緩存在 List<BaseModel> 這個靜態變量中,很遺憾的是并沒有在合適的時機進行釋放,造成了高峰期內存直線暴增,優化方案很簡單,就是修改業務邏輯咯,增加釋放內存的時機。

題外話

  • 如果你遇到的是這種 Strong Handles 的靜態變量,也可以直接用可視化的 dotMemory 查看。

當然你要保證你有足夠的內存,畢竟也算是小10G的dump ????, 我的 16G 內存一下子就被吃掉了。。。

  • 善于用 String 駐留池機制來優化,看看它的源碼定義吧。

public?sealed?class?String{[SecuritySafeCritical]public?static?string?Intern(string?str){if?(str?==?null){throw?new?ArgumentNullException("str");}return?Thread.GetDomain().GetOrInternString(str);}}

對于那些重復度很高的string,用駐留池機制可以節省千百倍的內存空間,至于為什么可以優化,可參考我之前的文章:字符串太占內存了,我想了各種奇思淫巧對它進行壓縮?。

END

工作中的你,是否已遇到 ...?

1. CPU爆高

2. 內存暴漲

3. 資源泄漏

4. 崩潰死鎖

5. 程序呆滯

等緊急事件,全公司都指望著你能解決...? 危難時刻才能展現你的技術價值,作為專注于.NET高級調試的技術博主,歡迎微信搜索: 一線碼農聊技術,免費協助你分析Dump文件,希望我能將你的踩坑經驗分享給更多的人。

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的记一次 .NET医疗布草API程序 内存暴涨分析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。