如何在 .NET 程序万种死法中有效的生成 Dump (上)
一:背景
相信很多人都知道通過(guò)?任務(wù)管理器?抓取dump,雖然簡(jiǎn)單粗暴,但無(wú)法滿足程序的無(wú)數(shù)種死法,比如:
內(nèi)存膨脹,程序爆炸
CPU爆高,程序累死
應(yīng)用無(wú)響應(yīng),用戶氣死
意外退出,和人生一樣
既然手工太弱雞,那有什么好的工具呢?除了 adplus,本文推薦一款神器?procdump, 下載地址:https://docs.microsoft.com/zh-cn/sysinternals/downloads/procdump ,還能支持 linux ????????????,具體怎么安裝就不細(xì)說(shuō)了。
二:內(nèi)存膨脹,程序爆炸
內(nèi)存膨脹?這種情況我相信很有朋友都遇到過(guò),我見(jiàn)過(guò)最多的案例就是用了小緩存 static,然后有意無(wú)意的忘記釋放,導(dǎo)致無(wú)限堆積終爆炸,那這種怎么用 procdump 去抓呢?
為了方便演示,我先寫(xiě)一個(gè)無(wú)限分配內(nèi)存的例子。
static?void?Main(string[]?args){List<string>?list?=?new?List<string>();for?(int?i?=?0;?i?<?int.MaxValue;?i++){list.Add(string.Join(",",?Enumerable.Range(0,?10000)));}Console.ReadLine();}將程序跑起來(lái)后,設(shè)置 procdump 在內(nèi)存超過(guò) 1G 的時(shí)候自動(dòng)抓取全內(nèi)存 dump,使用如下命令.
C:\Windows\system32>procdump??ConsoleApp2?-m?1024?-ma?E:\net5\ConsoleApp1\ConsoleApp2\bin\DebugProcDump?v10.0?-?Sysinternals?process?dump?utility Copyright?(C)?2009-2020?Mark?Russinovich?and?Andrew?Richards Sysinternals?-?www.sysinternals.comProcess:???????????????ConsoleApp2.exe?(24112) Process?image:?????????E:\net5\ConsoleApp1\ConsoleApp2\bin\Debug\ConsoleApp2.exe CPU?threshold:?????????n/a Performance?counter:???n/a Commit?threshold:??????>=?1024?MB Threshold?seconds:?????10 Hung?window?check:?????Disabled Log?debug?strings:?????Disabled Exception?monitor:?????Disabled Exception?filter:??????[Includes]*[Excludes] Terminate?monitor:?????Disabled Cloning?type:??????????Disabled Concurrent?limit:??????n/a Avoid?outage:??????????n/a Number?of?dumps:???????1 Dump?folder:???????????E:\net5\ConsoleApp1\ConsoleApp2\bin\Debug\ Dump?filename/mask:????PROCESSNAME_YYMMDD_HHMMSS Queue?to?WER:??????????Disabled Kill?after?dump:???????DisabledPress?Ctrl-C?to?end?monitoring?without?terminating?the?process.[21:23:43]?Commit:????1087Mb [21:23:43]?Dump?1?initiated:?E:\net5\ConsoleApp1\ConsoleApp2\bin\Debug\ConsoleApp2.exe_210323_212343.dmp [21:23:43]?Dump?1?writing:?Estimated?dump?file?size?is?1179?MB. [21:23:44]?Dump?1?complete:?1179?MB?written?in?1.3?seconds [21:23:44]?Dump?count?reached.從最后五行可以看出,當(dāng)內(nèi)存達(dá)到?1087M?的時(shí)候自動(dòng)生成了 dump 文件,接下來(lái)用 windbg 看一看。
查看當(dāng)前 process 的內(nèi)存占用量,使用?!address -summary?即可
看到上面?PAGE_READWRITE?行的?(1.055 GB)?嗎?和剛才 Console 中的 1087M 遙相呼應(yīng),沒(méi)毛病。
尋找大對(duì)象,在托管堆中使用?!dumpheap -stat -min 1024?即可
從輸出的最后一行可以看出,System.String?有1w多個(gè),接下來(lái)可以增加 ?-type?屬性篩選出?>10k?的字符串。
0:000>?!dumpheap?-type?System.String?-min?10240Address???????MT?????Size 03c75568?65d424e4????97792????? 03c8d378?65d424e4????97792???? 4a855060?65d424e4????97792?????Statistics:MT????Count????TotalSize?Class?Name 65d424e4????11452???1119913984?System.String Total?11452?objects0:000>?!gcroot?4a855060 Thread?36e4: ***?WARNING:?Unable?to?verify?checksum?for?ConsoleApp2.exe00b3f358?012108d1?ConsoleApp2.Program.Main(System.String[])?[E:\net5\ConsoleApp1\ConsoleApp2\Program.cs?@?18]ebp+18:?00b3f370->??02c71fd8?System.Collections.Generic.List`1[[System.String,?mscorlib]]->??02cce2ec?System.String[]->??4a855060?System.StringFound?1?unique?roots?(run?'!GCRoot?-all'?to?see?all?roots).從最后的?!gcroot?看,確實(shí)是被?Program.cs:18?行的 List 所持有,到此水落石出。
三:CPU爆高,程序累死
說(shuō)起CPU爆高的案例,我發(fā)現(xiàn)更多的是在?非托管堆?上,比如GC回收,爭(zhēng)搶鎖等,很少有人能傻到在?托管層?上把cpu搞起來(lái)。
對(duì)了,分析CPU 爆高有一個(gè)小技巧,那就是連續(xù)抓 dump 快照,看兩個(gè) dump 中的線程運(yùn)行情況,這時(shí)候就非常適合 procdump,先來(lái)看測(cè)試代碼。
class?Program{static?void?Main(string[]?args){Parallel.For(0,?int.MaxValue,?(i)?=>{while?(true){}});Console.ReadLine();}}現(xiàn)在我設(shè)定?連續(xù) 5s 內(nèi) CPU 超過(guò) 70% 抓取 dump,直到 2 個(gè)為止?。
C:\Windows\system32>procdump??ConsoleApp2?-s?5?-n?2?-c?70?E:\net5\ConsoleApp1\ConsoleApp2\bin\DebugProcDump?v10.0?-?Sysinternals?process?dump?utility Copyright?(C)?2009-2020?Mark?Russinovich?and?Andrew?Richards Sysinternals?-?www.sysinternals.comProcess:???????????????ConsoleApp2.exe?(22152) Process?image:?????????E:\net5\ConsoleApp1\ConsoleApp2\bin\Debug\ConsoleApp2.exe CPU?threshold:?????????>=?70%?of?system Performance?counter:???n/a Commit?threshold:??????n/a Threshold?seconds:?????5 Hung?window?check:?????Disabled Log?debug?strings:?????Disabled Exception?monitor:?????Disabled Exception?filter:??????[Includes]*[Excludes] Terminate?monitor:?????Disabled Cloning?type:??????????Disabled Concurrent?limit:??????n/a Avoid?outage:??????????n/a Number?of?dumps:???????2 Dump?folder:???????????E:\net5\ConsoleApp1\ConsoleApp2\bin\Debug\ Dump?filename/mask:????PROCESSNAME_YYMMDD_HHMMSS Queue?to?WER:??????????Disabled Kill?after?dump:???????DisabledPress?Ctrl-C?to?end?monitoring?without?terminating?the?process.[22:25:47]?CPU:?95%?1s [22:25:48]?CPU:?100%?2s [22:25:50]?CPU:?96%?3s [22:25:51]?CPU:?98%?4s [22:25:52]?CPU:?99%?5s?(Trigger) [22:25:53]?Dump?1?initiated:?E:\net5\ConsoleApp1\ConsoleApp2\bin\Debug\ConsoleApp2.exe_210323_222553.dmp [22:25:54]?Dump?1?complete:?5?MB?written?in?0.3?seconds [22:25:56]?CPU:?88%?1s [22:25:58]?CPU:?93%?2s [22:26:00]?CPU:?89%?3s [22:26:02]?CPU:?89%?4s [22:26:04]?CPU:?95%?5s?(Trigger) [22:26:05]?Dump?2?initiated:?E:\net5\ConsoleApp1\ConsoleApp2\bin\Debug\ConsoleApp2.exe_210323_222605.dmp [22:26:06]?Dump?2?complete:?5?MB?written?in?0.4?seconds [22:26:07]?Dump?count?reached.從最后輸出中可以看到,連續(xù)?5s?CPU 超過(guò)了 70% 抓取了 dump,總共來(lái)了2個(gè)。
現(xiàn)在 dump 有了,接下來(lái)用兩個(gè) windbg 實(shí)例打開(kāi),驗(yàn)證下 dump 的生成時(shí)間,如下圖所示:
從圖中可以看到,兩個(gè) dump 生成時(shí)間相隔 12s,而且通過(guò)?!runaway?發(fā)現(xiàn)下面的線程:
14:2cb8
19:3f8c
...
都運(yùn)行了長(zhǎng)達(dá) 10s ,這說(shuō)明什么?說(shuō)明這二個(gè)線程應(yīng)該在某個(gè)地方死循環(huán)了。。。對(duì)吧。。。
切到 14 號(hào)線程通過(guò)?!clrstack?看調(diào)用堆棧即可,都是死在?ConsoleApp2.Program+c.b__0_0(Int32)?這里出不來(lái)。。。
四:總結(jié)
感覺(jué)篇幅有點(diǎn)長(zhǎng)了,就先說(shuō)到這里吧,有興趣的話,可以把 procdump 拉下來(lái)玩一玩 ????。
END
工作中的你,是否已遇到 ...?
1. CPU爆高
2. 內(nèi)存暴漲
3. 資源泄漏
4. 崩潰死鎖
5. 程序呆滯
等緊急事件,全公司都指望著你能解決...? 危難時(shí)刻才能展現(xiàn)你的技術(shù)價(jià)值,作為專注于.NET高級(jí)調(diào)試的技術(shù)博主,歡迎微信搜索: 一線碼農(nóng)聊技術(shù),免費(fèi)協(xié)助你分析Dump文件,希望我能將你的踩坑經(jīng)驗(yàn)分享給更多的人。
總結(jié)
以上是生活随笔為你收集整理的如何在 .NET 程序万种死法中有效的生成 Dump (上)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 通过Dapr实现一个简单的基于.net的
- 下一篇: 监控系统简介:使用 Prometheus