如何创建、使用和调试 .NET 应用程序崩溃转储

转自:https://michaelscodingspot.com/how-to-create-use-and-debug-net-application-crash-dumps-in-2019/?_x_tr_sl&_x_tr_tl&_x_tr_hl

.NET 故障排除中最有用的工具之一是转储文件。这可能是调试崩溃和生产调试的最佳工具。

在本文中,我们将了解转储文件究竟是什么、它们为何如此有用以及如何正确使用它们。您将看到创建转储文件的所有方法,将它们与符号和源文件正确匹配,以及最终如何调试它们以解决问题。

虽然转储可用于本机程序和托管程序,但本文仅指托管 .NET 程序

目录:

.NET 中的转储文件是什么?

内存转储文件(.dmp文件)是给定时间(例如崩溃期间)程序内存的快照。使用转储文件,您可以查看当前执行的代码行、本地值的值和所有堆对象的值。换句话说,转储文件表示程序在捕获时的整个状态。

转储通常用于调试崩溃(Crash Dumps),但也有其他用途。从最常见到最少,它们是:

  • 调试崩溃的程序
  • 调试挂起的程序
  • 查找内存泄漏
  • 在不同的机器上或在不同的时间调试
  • 调试无法附加调试器的程序
  • 使用WinDbg 进行调试

转储类型

有 2 种转储文件类型:Full Memory DumpMinidump完整内存转储包含程序的整个内存。它可以变得非常大。

小型转储具有误导性名称。它是一种可配置的转储格式。它可以包含整个内存,占用与完整内存转储一样多的空间(甚至更多),或者它可以只包含每个配置的部分内存。来源

对于 .NET,我们将主要使用带有整个内存的 Dumps 以获得完整的调试体验。它可以是完整内存转储配置为包含整个内存空间小型转储

如何创建/捕获转储

有很多方法可以创建转储。我将展示一些更常见和推荐的:

1.调试时使用Visual Studio

调试时,转到调试 | Save Dump As...
这将使用 Heap保存小型转储,其中包括完整的内存空间。

2. 使用任务管理器

打开任务管理器,转到详细信息,右键单击所需进程并选择创建转储文件

这将创建一个完整的内存转储。

3. 使用 ProcDump

ProcDump SysInternal 工具包,这是一套非常有用的 Windows 开发工具。ProcDump 本身是一个用于创建转储的命令行工具。它可以按需生成转储或通过监视程序并在崩溃或挂起时创建转储。这是我捕获转储的首选工具。

立即创建具有完整内存的转储的简单用例是:

这会在您的工作目录中创建一个名为:[process name]_[date]_[time].dmp 的转储文件。

您可以监控内存使用情况、挂起的程序、CPU 使用情况、第一次机会异常等情况,并根据需要创建转储。例如,当myprogram.exe挂到名为的文件时,这会捕获转储 转储文件 .dmp

所有功能的信息都在这里

4. 使用进程浏览器

Process ExplorerSysInternal工具包中的另一个工具您可以找到哪些进程加载了某个 DLL 或句柄,当然可以查看活动线程、注册表项和创建转储。

右键单击任何进程并选择 Create Dump | Create Full Dump…

 

 

5. 崩溃时自动创建转储

您可以让 Windows 在程序崩溃时自动生成转储文件。这是通过 Windows 错误报告 (WER) 完成的。您可以在注册表中进行配置:

  1. 运行 regedit.exe
  2. 打开或创建密钥HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps
  3. 添加与您的程序同名的键 例如,Snagit32.exe
  4. 添加键:
    1. DumpFolder (REG_EXPAND_SZ) – 应在其中创建转储的文件夹
    2. DumpCount (REG_DWORD) – 在覆盖旧转储之前创建的最大转储数量。默认值为 10。
    3. DumpType (REG_DWORD) – Minidump (1) 或 Full dump (2)。对于.NET应用使用Full dump (2)。

注册表应如下所示:

调试转储

创建转储是简单的部分。真正的挑战是调试它们并理解问题。

有几种方法可以调试转储文件:

1. 使用 Visual Studio

可能最简单的方法是在 Visual Studio 中打开转储文件 (.dmp)。假设您可以匹配符号(.pdb 文件)和源文件,您将获得完整的调试体验。也就是说,您会看到代码就像站在断点上一样。如果它是Crash Dump,那么您将看到导致崩溃的异常。您还应该看到线程、调用堆栈、局部变量、加载的模块等。

使用 Visual Studio 进行调试的说明:

  1. 在 Visual Studio 中打开 .dmp 文件
  2. 点击“Debug with Managed Only”或“Debug with Mixed”

 

 

3.等待VS尝试加载符号并匹配到源代码。
4. 如果加载了符号,您将看到代码。否则,您应该看到调用堆栈、异常信息(如果在异常时捕获)以及可能的本地值。
5. 像在常规 Visual Studio 调试中一样调查异常或问题。

 

 

将符号和源代码文件与 Visual Studio 中的转储匹配

在最后的图片中您可以看到没有加载符号的转储是什么样子。可以看到里面的调用栈、本地值、异常信息、线程和加载的模块。通常,这足以找到问题。

通过加载符号文件,您还可以直接在 Visual Studio 中查看代码。为此,您将需要.pdb 文件和实际的源文件默认情况下,在每次构建后,符号(.pdb 文件)与程序集(.exe 和 .dll 文件)一起bin\Debugbin\Release目录中创建。建议使用包含的符号部署您的程序/NuGet。

重要的是要了解符号和源代码应该与创建转储时的版本完全匹配。否则,匹配将失败。

Visual Studio 尝试自行查找符号文件。它看起来在:

  1. 可执行文件所在的目录(您的bin\debugbin\release
  2. 打开的.dmp文件的目录
  3. 符号目录,可以在 Tools | Debugging | Symbols
  4. 符号服务器

因此,要加载符号,您只需将它们放在上述目录之一中。您还可以从 Visual Studio(如从模块窗口)手动加载单个符号。

如果您有程序集(.exe 和 .dll),那么您可以反编译它们以获得源代码并提取它们的符号。dotPeek这样的程序可以提取符号 + 源代码并充当符号服务器然后,您可以在 Visual Studio 的工具中添加该符号服务器

有两种技术可以自动从 .pdb 文件中获取源代码:Source Server和较新的Source Link我从来没有使用过它们,但我相信Source Link嵌入了一个链接到正确的git commit和相关的源代码版本。

2. 使用 WinDbg 调查转储

WinDbg被认为是调查转储文件的首选工具。现在,我不建议在简单的情况下使用它,在这种情况下,您可以在 Visual Studio 中打开转储并在图形 IDE 中获取相同的信息。

话虽如此,Visuals Studio 在能力方面仍在追赶。WinDbg 可以探索对象堆、提取模块、发现死锁以及做很多 VS 仍然做不到的事情。

如果您不熟悉 WinDbg,它是一个(主要)Windows 命令行调试工具。WinDbg 可用于本机程序或带有SOS 调试扩展的托管 .NET 程序 

开始使用 WinDbg:

  1. 使用Windows 调试工具安装 WinDbg  
  2. 打开正确的 WinDbg 版本——有 x86 和 x64 windbg.exe可执行文件,它们应该与 Dump 的位数匹配。查看以下文件夹:
    C:\Program Files (x86)\Windows Kits\10\Debuggers\x64
    C:\Program Files (x86)\Windows Kits\10\Debuggers\x86
  3. 在 WinDbg 中,打开您保存的转储 (Ctrl + D)
  4. 开启详细日志
      !sym noisy 
  5. 设置符号搜索路径 
    .sympath srv*https://msdl.microsoft.com/download/symbols 
    .sympath+ cache*C:\debug\symbols 
    .sympath+ C:\MyApp\bin\Debug
  6. 强制重新加载符号 
     .reload 
     ld* 
  7. 加载 SOS 扩展
     .loadby sos clr 
  8. 继续执行其他命令

如指令#5 所示,您可以从任何目录或符号服务器加载符号(如果有的话)。在这方面,它类似于 Visual Studio。

那么你可以用 WinDbg 做什么呢?

无论您可以使用Visual Studio做什么,您也可以使用WinDbg等等。这里有一些你可以用WinDbg做而你不能用 VS 做的事情:

  • 探索对象堆(按类型、内存消耗)
  • 按字符串搜索对象堆
  • 查看线程 CPU 消耗
  • 查看有关对象的(更详细的)信息(方法表、EEClass、大小、字段...)
  • 查看内存消耗(按类型,对于 X 类型的对象,..)
  • 显示所有锁定的对象
  • 查看每个线程的锁计数
  • 自动检测死锁(SOSEX)
  • 探索垃圾收集器——代的内容,终结器队列,......
  • 提取模块(如果您只有 Dump,则很有用,用于从符号服务器反编译和创建符号服务器)

我可能错过了一些或添加了一些 Visual Studio 也可以做的事情,VS 一直在变得更好。但总体思路是 WinDbg 几乎可以做任何事情,尽管可能有点难以处理。这是有关托管转储的 WinDbg 命令cheat sheet这包括使用SOSEX 的命令,这是 WinDbg 托管调试的另一个有用扩展。

3. 使用其他工具调试转储:CDB & NTSD、DumpMiner 和 SuperDump

还有一些其他的转储文件调试工具:

  • CDB和 NTSD 是类似于 WinDbg 的命令行调试器。不同之处在于 CDB 根本没有 UI,而 WinDbg 确实有一些 UI,如内存地址链接。
  • DumpMiner是一个使用ClrMD调试转储的工具它在用户友好的 UI 中提供了许多 WinDbg 功能。它可以调查调用堆栈、线程、大对象堆、终结器、处理程序等。
  • SuperDump – 还允许以用户友好的方式提供类似 WinDbg 的功能。这是一个基于云的解决方案,因此您必须将转储上传到他们的服务器才能使用它。SuperDump 包含许多功能

WinDbg 预览

我们在本文中讨论了很多关于 WinDbg 的内容,所有示例都在经典的WinDbg 版本中展示。但是,2017 年 8 月发布一个新版本的 WinDbg 。它现在被称为WinDbg 预览版

新版本仍然是基于命令行的,但它包含了许多可视化、突出显示、键盘快捷键、调试窗口和新功能不知道它是否会像在 Visual Studio 中调试一样好,但这肯定是朝着正确方向迈出的一步。

.NET 核心转储

就 .NET Core 而言,一切都与 .NET 框架一样好。您可以在 Visual Studio (2017) 和 WinDbg 中打开 .NET Core Dumps。WinDbg的唯一区别是您必须加载SOS coreclr 而不是常规clr  : .loadby sos coreclr

甚至可以在 Linux 中调试 .NET Core 转储(请参阅Sasha Goldshtein 的文章)。

总结

正如您在本文中读到的,调试转储不再自动转到WinDbg在 2019 年,我们有许多工具可供我们使用,可以使调试工作变得更加容易。其中一些工具是 Visual Studio、DumpMinerSuperDumpWinDbg Preview

Crash Dumps 对我来说总是一件可怕的事情。随着岁月的流逝,我对它们越来越熟悉,慢慢地它们变得不那么可怕,也更加友好。所以我希望这篇文章能帮助你与 Dump Files 成为更好的朋友。

 

posted @ 2021-10-21 15:47  ntwo  阅读(1351)  评论(0)    收藏  举报