如何在 NET 程序万种死法中有效的生成 Dump (下)
一:背景
上一篇我們聊到了如何通過 procdump 抓取 cpu爆高 和 內存暴漲 兩種情況,這一篇再聊聊如何去抓程序 掛死 和 意外退出。
二:程序掛死
1. 定義
程序掛死 簡單的說就是程序沒有響應,既然沒響應了,可能 死鎖, 可能 負載過大線程池耗盡 等等情況,萬千世界,啥情況都有????????????。
既然是用 procdump 去抓,我得先了解下它對 掛死 (hung on) 的定義?
-h?Write?dump?if?process?has?a?hung?window?(does?not?respond?to?window?messages?for?at?least?5?seconds).從上面的定義看,人家貌似是判斷窗口是否在指定時間內響應 windows消息 來判別的,我知道你在想什么????,你尋找的web請求響應時間過長,這種場景通過 -h 是抓不到的,我感覺它特別適合那些帶有 GUI 程序的抓取,比如說:(WPF,Winform) 。
2. 案例演示
現在我準備創建一個簡單的 winform 程序,在 button 事件中故意讓主線程sleep造成程序假死,參考代碼如下:
public?partial?class?Form1?:?Form{public?Form1(){InitializeComponent();}private?void?button1_Click(object?sender,?EventArgs?e){Thread.Sleep(1000?*?10);MessageBox.Show("clicked?me!");}}接下來啟動 cmd 窗口,輸入:
C:\Windows\system32>procdump?-ma?-h?-w?WindowsFormsApp1.exe?E:\net5\hungwindow.dmpProcDump?v10.0?-?Sysinternals?process?dump?utility Copyright?(C)?2009-2020?Mark?Russinovich?and?Andrew?Richards Sysinternals?-?www.sysinternals.comWaiting?for?process?named?WindowsFormsApp1.exe...啟動程序后點擊 button 讓 winform 假死,可以看到 procdump 在 5s 之后自動輸出了dump。
C:\Windows\system32>procdump?-ma?-h?-w?WindowsFormsApp1.exe?E:\net5\hungwindow.dmpPress?Ctrl-C?to?end?monitoring?without?terminating?the?process.[14:49:53]?Hung?Window: [14:49:53]?Dump?1?initiated:?E:\net5\hungwindow.dmp [14:49:53]?Dump?1?writing:?Estimated?dump?file?size?is?303?MB. [14:49:53]?Dump?1?complete:?303?MB?written?in?0.7?seconds [14:49:54]?Dump?count?reached.然后用 windbg 看看每一個線程都在做什么?
0:000>?~*e?!clrstack OS?Thread?Id:?0x6698?(0) Child?SP???????IP?Call?Site 00cfeb60?7722327c?[HelperMethodFrame:?00cfeb60]?System.Threading.Thread.SleepInternal(Int32) 00cfebe4?5da9be7b?System.Threading.Thread.Sleep(Int32) 00cfebec?02d1238d?WindowsFormsApp1.Form1.button1_Click(System.Object,?System.EventArgs)?[E:\net5\ConsoleApp1\WindowsFormsApp1\Form1.cs?@?23] 00cfec04?5a3b95bb?System.Windows.Forms.Control.OnClick(System.EventArgs) 00cfec18?5a3bbe57?System.Windows.Forms.Button.OnClick(System.EventArgs) ...三:意外退出
1. 概念
意外退出 我想很多朋友都遇到過,本來 Console 程序跑的好好地,半夜收到報警短信.... ?還有用戶反饋,你那終端可行呀,點了幾下就掛掉了。。。????????????
有些朋友可能在想,sd,這問題還不簡單,加一個全局 未處理異常 不就好啦???真搞不懂怎么想的 ????????????。
哈哈,總以為 全局異常處理 能夠包治百病,還是太年輕了,記得上一家公司用了阿里的sdk,底層用了 C++ 封裝,程序莫名退出了,全局異常處理也沒任何日志,說到這里我想你也知道了,非托管層拋出的異常,托管層這時候就是弟弟,就這么簡單????????????
2. 演示
我準備在程序中拋出一個簡單的 DivideByZeroException ,方便讓程序退出。
public?class?Program{public?static?void?Main(string[]?args){var?result?=?CalcDAL();Console.WriteLine($"result={result}");Console.ReadLine();}public?static?int?CalcDAL(){try{var?query?=?"0";Thread.Sleep(2000);??//do?sth...return?0?/?Convert.ToInt32(query);}catch?(Exception?ex){Console.WriteLine(ex.Message);throw;}}}程序跑起來后,在 procdump 上用 -e 命令抓取。
C:\Windows\system32>procdump?-ma?-e??-w?ConsoleApp1.exe?E:\net5\test.dmpProcDump?v10.0?-?Sysinternals?process?dump?utility Copyright?(C)?2009-2020?Mark?Russinovich?and?Andrew?Richards Sysinternals?-?www.sysinternals.comWaiting?for?process?named?ConsoleApp1.exe...Press?Ctrl-C?to?end?monitoring?without?terminating?the?process.[15:29:56]?Exception:?04242420 [15:29:58]?Exception:?C0000094.INT_DIVIDE_BY_ZERO [15:29:58]?Exception:?C0000094.INT_DIVIDE_BY_ZERO [15:29:58]?Exception:?C0000094.INT_DIVIDE_BY_ZERO [15:29:58]?Unhandled:?C0000094.INT_DIVIDE_BY_ZERO [15:29:58]?Dump?1?initiated:?E:\net5\test-2.dmp [15:29:58]?Dump?1?writing:?Estimated?dump?file?size?is?50?MB. [15:29:59]?Dump?1?complete:?50?MB?written?in?0.2?seconds [15:29:59]?Dump?count?reached.從輸出看,萬事ok。
3. 拓展
不知道有沒有朋友還記得 VS 有一個 異常斷點 嗎?表示當某種異常拋出時,程序自動進入斷點處調試狀態,這是一個幫助找到bug的利器,但還是有一定限制的,畢竟程序都跑在生產上,你也不能把 vs 搬過去,也不可能搞個遠程調試啥的,所以當程序拋出了某一種異常后,怎么自動生成一個 dump 呢???
在強大的 procdump 面前這些都是弟弟,????????,主要通過下面兩種方式進行異常碰撞檢索。
通過 異常類型 抓取
何為 異常類型,比如本節的 DivideByZeroException 異常,通過在 procdump 中設置 -e 1 -f DivideByZeroException 即可。
把 CalcDAL() 方法中的 throw 去掉,保證程序不異常退出。
public?static?int?CalcDAL(){try{var?query?=?"0";Thread.Sleep(2000);??//do?sth...return?0?/?Convert.ToInt32(query);}catch?(Exception?ex){Console.WriteLine(ex.Message);return?0;}}然后用 proddump 輸入如下命令。
C:\Windows\system32>procdump?-ma??-w?-e?1?-f???"divide?by?zero"??-w?ConsoleApp1.exe?E:\net5\test.dmpProcDump?v10.0?-?Sysinternals?process?dump?utility Copyright?(C)?2009-2020?Mark?Russinovich?and?Andrew?Richards Sysinternals?-?www.sysinternals.comWaiting?for?process?named?ConsoleApp1.exe...Press?Ctrl-C?to?end?monitoring?without?terminating?the?process.CoreCLR?Version:?v5.0.3[15:44:15]?Exception:?E0434F4D.System.DivideByZeroException?("Attempted?to?divide?by?zero.") [15:44:15]?Dump?1?initiated:?E:\net5\test-3.dmp [15:44:16]?Dump?1?writing:?Estimated?dump?file?size?is?50?MB. [15:44:16]?Dump?1?complete:?50?MB?written?in?0.2?seconds [15:44:16]?Dump?count?reached.看到上面的 Exception: E0434F4D.System.DivideByZeroException ("Attempted to divide by zero.") 了嘛?哈哈,已經成功捕獲啦,是不是挺有意思????。
通過 異常信息 抓取
用 異常信息 的話,我覺得更加靈活,比如我搜索一下:divide by zero 關鍵詞就能成功捕獲。
C:\Windows\system32>procdump?-ma??-w?-e?1?-f???"divide?by?zero"??-w?ConsoleApp1.exe?E:\net5\test.dmp[15:46:34]?Exception:?E0434F4D.System.DivideByZeroException?("Attempted?to?divide?by?zero.") [15:46:34]?Dump?1?initiated:?E:\net5\test-4.dmp [15:46:34]?Dump?1?writing:?Estimated?dump?file?size?is?49?MB. [15:46:34]?Dump?1?complete:?49?MB?written?in?0.2?seconds [15:46:35]?Dump?count?reached.四:總結
混混沌沌寫了這么多,上下兩篇四種抓取方法我想你都學會了吧,萬事開頭難,有了dump,接下來就是好好研究咯!
總結
以上是生活随笔為你收集整理的如何在 NET 程序万种死法中有效的生成 Dump (下)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 监控系统简介(二):使用 App Met
- 下一篇: NET问答: 有最干净利落的读写文件方式