如何在 NET 程序万种死法中有效的生成 Dump (下)

C# 小时候可胖了 37℃ 0评论

一:背景

上一篇我们聊到了如何通过

1
procdump

抓取

1
cpu爆高

1
内存暴涨

两种情况,这一篇再聊聊如何去抓程序

1
挂死

1
意外退出

二:程序挂死

1. 定义

1
程序挂死

简单的说就是程序没有响应,既然没响应了,可能

1
死锁

, 可能

1
负载过大线程池耗尽

等等情况,万千世界,啥情况都有????????????。

既然是用

1
procdump

去抓,我得先了解下它对

1
挂死 (hung on)

的定义?


1
-h  Write dump if process has a hung window (does not respond to window messages for at least 5 seconds).

从上面的定义看,人家貌似是判断窗口是否在指定时间内响应

1
windows消息

来判别的,我知道你在想什么????,你寻找的web请求响应时间过长,这种场景通过 -h 是抓不到的,我感觉它特别适合那些带有 GUI 程序的抓取,比如说:(WPF,Winform) 。

2. 案例演示

现在我准备创建一个简单的

1
winform

程序,在 button 事件中故意让主线程sleep造成程序假死,参考代码如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
    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 窗口,输入:


1
2
3
4
5
6
7
8
C:Windowssystem32>procdump -ma -h -w WindowsFormsApp1.exe E:
et5hungwindow.dmp

ProcDump v10.0 - Sysinternals process dump utility
Copyright (C) 2009-2020 Mark Russinovich and Andrew Richards
Sysinternals - www.sysinternals.com

Waiting for process named WindowsFormsApp1.exe...

启动程序后点击 button 让 winform 假死,可以看到 procdump 在 5s 之后自动输出了dump。


1
2
3
4
5
6
7
8
9
10
11
12
C:Windowssystem32>procdump -ma -h -w WindowsFormsApp1.exe E:
et5hungwindow.dmp


Press Ctrl-C to end monitoring without terminating the process.

[14:49:53] Hung Window:
[14:49:53] Dump 1 initiated: E:
et5hungwindow.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 看看每一个线程都在做什么?


1
2
3
4
5
6
7
8
9
10
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:
et5ConsoleApp1WindowsFormsApp1Form1.cs @ 23]
00cfec04 5a3b95bb System.Windows.Forms.Control.OnClick(System.EventArgs)
00cfec18 5a3bbe57 System.Windows.Forms.Button.OnClick(System.EventArgs)
...

三:意外退出

1. 概念

1
意外退出

我想很多朋友都遇到过,本来 Console 程序跑的好好地,半夜收到报警短信.... 还有用户反馈,你那终端可行呀,点了几下就挂掉了。。。????????????

有些朋友可能在想,sd,这问题还不简单,加一个全局

1
未处理异常

不就好啦??? 真搞不懂怎么想的 ????????????。

哈哈,总以为

1
全局异常处理

能够包治百病,还是太年轻了,记得上一家公司用了阿里的sdk,底层用了 C++ 封装,程序莫名退出了,全局异常处理也没任何日志,说到这里我想你也知道了,非托管层抛出的异常,托管层这时候就是弟弟,就这么简单????????????

2. 演示

我准备在程序中抛出一个简单的

1
DivideByZeroException

,方便让程序退出。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    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 上用

1
-e

命令抓取。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
C:Windowssystem32>procdump -ma -e  -w ConsoleApp1.exe E:
et5 est.dmp

ProcDump v10.0 - Sysinternals process dump utility
Copyright (C) 2009-2020 Mark Russinovich and Andrew Richards
Sysinternals - www.sysinternals.com

Waiting 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:
et5 est-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 有一个

1
异常断点

吗? 表示当某种异常抛出时,程序自动进入断点处调试状态,这是一个帮助找到bug的利器,但还是有一定限制的,毕竟程序都跑在生产上,你也不能把 vs 搬过去,也不可能搞个远程调试啥的,所以当程序抛出了某一种异常后,怎么自动生成一个 dump 呢???

在强大的 procdump 面前这些都是弟弟,????????,主要通过下面两种方式进行异常碰撞检索。

  • 通过
    1
    异常类型

    抓取

何为

1
异常类型

,比如本节的

1
DivideByZeroException

异常,通过在 procdump 中设置

1
-e 1 -f DivideByZeroException

即可。

1
CalcDAL()

方法中的 throw 去掉,保证程序不异常退出。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
        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;
            }
        }

然后用

1
proddump

输入如下命令。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
C:Windowssystem32>procdump -ma  -w -e 1 -f   "divide by zero"  -w ConsoleApp1.exe E:
et5 est.dmp

ProcDump v10.0 - Sysinternals process dump utility
Copyright (C) 2009-2020 Mark Russinovich and Andrew Richards
Sysinternals - www.sysinternals.com

Waiting 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:
et5 est-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.

看到上面的

1
Exception: E0434F4D.System.DivideByZeroException ("Attempted to divide by zero.")

了嘛? 哈哈,已经成功捕获啦,是不是挺有意思????。

  • 通过
    1
    异常信息

    抓取

1
异常信息

的话,我觉得更加灵活,比如我搜索一下:

1
divide by zero

关键词就能成功捕获。


1
2
3
4
5
6
7
8
9
C:Windowssystem32>procdump -ma  -w -e 1 -f   "divide by zero"  -w ConsoleApp1.exe E:
et5 est.dmp

[15:46:34] Exception: E0434F4D.System.DivideByZeroException ("Attempted to divide by zero.")
[15:46:34] Dump 1 initiated: E:
et5 est-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,接下来就是好好研究咯!

更多高质量干货:参见我的 GitHub: dotnetfly

图片名称

转载请注明:九层楼 » 如何在 NET 程序万种死法中有效的生成 Dump (下)

喜欢 (0)
发表我的评论
取消评论
表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址