Windows应用的crash dump收集入门 - 先搞清楚 WER / ProcDump / WinDbg怎么分工

· · Windows开发, 故障排查, crash dump, WER, ProcDump, WinDbg

在 Windows 应用上,只要出现「偶尔才会崩溃」这种症状,光靠日志往往追查不下去。

特别是下列情境:

  • 只在客户环境会发生
  • 有捕获到异常信息,但调用端的上下文不够
  • 不只是 C# / .NET 的 managed 层,还牵涉 COM、P/Invoke、原生 DLL、厂商 SDK
  • 只有在长时间运行后才崩溃

这时候 crash dump 就派得上用场。只要在 crash 当下把进程状态存成文件,之后就能读到异常代码、挂掉那条 thread 的堆栈、当时加载的模块、以及部分或整块的内存。

在 Windows 上,思路顺序是:先用 WER 的 LocalDumps,有需要再搭配 Sysinternals 的 ProcDump;真的想自己掌控了,再用 MiniDumpWriteDump。本文就以 Windows 桌面应用、常驻应用、Windows 服务、设备集成工具等为前提,整理 crash dump 收集的第一步。

1. 先下结论

先把最要掌握的重点列出来:

  • 按应用单独配置 WER LocalDumps 是最稳妥的做法,不用额外部署工具,也能在 crash 后把 dump 留在本地。
  • 复现率低的现场调查、或要看 first chance exception / hang,就用 ProcDump
  • 自研收集放到最后再想 大概刚好。真的需要再评估 MiniDumpWriteDump 就行。
  • 和 dump 同等重要的是 PDB 与发布 binary 的保存。只有 dump 没有符号,能读到的信息会大幅减少。
  • full dump 威力大,但文件大小与敏感信息泄露风险也大。保存位置、保留份数、访问权限、分享流程要先定好。

入门阶段建议的配置大概是这样:

环境 起手式
开发机/验证机 按应用单独配置 WER LocalDumps,先用 DumpType=2 取 full dump
客户环境/现场机 依容量与敏感度要求选 DumpType=12;只在必要时补上 ProcDump
长时间运行或 hang 调查 WER 之外再评估 ProcDump 的 -h-e 1
想自带 UI、附带日志 以独立进程为前提,用 MiniDumpWriteDump 做自研收集

简单说就是:先 WER,再 ProcDump,最后自研。反过来的顺序做,设计通常会变重。

2. crash dump 能告诉我们什么

crash dump 是「那一刻的快照」,比起监控录像,它更像事故现场的静止画面。

所以下列信息通常很容易拿到:

  • 是哪个异常代码
  • 是哪条 thread 挂掉
  • 当下的调用堆栈
  • 当时加载的模块
  • 依你包进多少内存,还能看到 heap 的状态、对象内容

但下列信息光靠 dump 就比较不够:

  • 走到这一步的时序
  • 几小时前就在上升的趋势
  • 和通信或设备之间的外部状态
  • 崩溃前的输入或业务情境

所以实务上 不要只靠 dump 单打独斗,要搭配日志与 heartbeat

3. 收集方法全景

入门阶段要掌握的 Windows 应用 dump 收集方式,有下列 4 种:

方法 适合情境 优势 注意事项
WER LocalDumps 想先常态化的 crash 收集 Windows 内置,易按应用单独配置 主要针对 crash;hang 与细部条件分流较弱
ProcDump 复现率低的调查、hang、first chance exception 触发条件多,容易在现场部署 变成外部工具的运维
任务管理器的创建 dump 手动抓当下状态 GUI 现场抓 不是自动收集
MiniDumpWriteDump 想做自研诊断功能 容易把附带日志或自定义 metadata 绑一起 写不好反而会把自己搞坏

对入门者来说,比起「用什么抓」,更要先决定「在什么条件」「抓到哪」「抓多大」

4. 起手式推荐 WER LocalDumps

4.1 先看的注册表值

Windows Error Reporting (WER) 内置了 LocalDumps,可以在 crash 后把 user-mode dump 存到本地。不用额外分发工具,起手式相当好用。

基本 key 是:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps

你可以在这里放全局设置,但实务上更建议把设置放在 按应用单独的子 key 下。

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe

最先看的值有 3 个:

含义 起手式建议
DumpFolder dump 的输出位置 划一个专用文件夹
DumpCount 保留份数 从 5〜10 起
DumpType 0=自定义、1=mini、2=full 先用 2;容量吃紧再改 1

4.2 按应用单独的配置示例

举例来说,想把 MyApp.exe 的 full dump 存到 C:\CrashDumps\MyApp,最多保留 10 份,可以这样设置:

reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /v DumpFolder /t REG_EXPAND_SZ /d "C:\CrashDumps\MyApp" /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /v DumpCount /t REG_DWORD /d 10 /f
reg add "HKLM\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps\MyApp.exe" /v DumpType /t REG_DWORD /d 2 /f

这段的重点:

  • 范围限定到 MyApp.exe,不是全局
  • 输出位置划到专用文件夹
  • 起手式先用 full dump
  • 保留份数限制为 10

4.3 确认真的有抓到

设置好之后,不要直接等正式环境自然发生,一定要先在验证环境亲自抓一次 比较安全。

确认重点:

  1. .dmp 会不会出现在预期文件夹
  2. 文件大小是否符合运维设想
  3. 用 WinDbg 能不能打开
  4. 事件查看器的 Application 日志有没有对应 crash 事件

5. 何时用 ProcDump

WER 就够用的情境不少,但下列情境 ProcDump 更方便:

  • 不想常设注册表项
  • 只想监视某个已在跑的进程
  • 只想监视下一次启动的进程
  • 要看 first chance exception
  • 要抓 hang
  • 想用性能计数器或其他条件触发

5.1 常用选项

入门阶段只要记下列这些,就能打相当多仗:

选项 含义
-ma full dump
-mp MiniPlus dump
-e 未处理异常时抓 dump
-e 1 first chance / second chance 异常都抓
-h 窗口 hang 时抓
-w 等待目标进程启动
-x 由 ProcDump 启动并监视目标
-n 最多抓几份 dump
-accepteula 首次 EULA 自动同意

5.2 代表性命令

对已启动的进程,未处理异常时抓 full dump

procdump -accepteula -ma -e 1234 C:\CrashDumps\MyApp

等下次启动,未处理异常时抓 full dump

procdump -accepteula -ma -e -w MyApp.exe C:\CrashDumps\MyApp

由 ProcDump 启动并继续监视

procdump -accepteula -ma -e -x C:\CrashDumps\MyApp MyApp.exe

连 first chance exception 也要抓

procdump -accepteula -ma -n 3 -e 1 MyApp.exe C:\CrashDumps\MyApp

要抓 hang

procdump -accepteula -h MyApp.exe C:\CrashDumps\MyApp

5.3 为什么不要把 -i 当起手式

ProcDump 有 -i 可以注册成 postmortem debugger,功能很强,但 会影响整台机器的 crash 时行为,入门阶段拿它来起手式太重。

起手式建议从 WER 的按应用单独配置ProcDump 的 -w / -x / 指定 PID 开始,比较好掌握。

6. 自研收集用 MiniDumpWriteDump 的思路

自研收集适合下列情境:

  • 想在 UI 放一个「保存诊断信息」按钮
  • 想把 dump、日志、配置、trace ID 绑在一起
  • 想连同关联的子进程或辅助进程一起打包
  • 上传前想做自研的数据遮罩或压缩

这里主角 API 是 MiniDumpWriteDump

不过它有一些特性,入门阶段最不要偏掉的有 2 点:

  1. 如果可以,从另一个进程去 dump 目标进程
  2. DbgHelp 系列以 single-threaded 的前提使用

7. mini / full / 中型 dump 怎么选

这里相当多人犹豫。实务上照下表思考会比较顺:

种类 适合情境 优势 注意事项
mini dump 想先广泛分发、方便分享 小、好传 能还原的状态深度有限
full dump 以查原因为优先,牵涉原生边界或 heap 信息最多 文件大、敏感信息泄露风险高
MiniPlus / Custom mini 不够、full 又太重 取平衡 需要调参的知识

给入门者的建议其实很单纯:

  • 开发机/验证机直接 full dump
  • 客户环境依运维条件选 mini 或 full
  • 怀疑是内存损坏、原生 DLL、COM、P/Invoke、或长时间运行后的状态异常,偏 full

8. 运维上要先决定的事

dump 收集常常是运维层面先出事,而不是实现层面。请先把下列事项梳理清楚。

8.1 PDB 与 binary 要怎么保存

这件事最重要。

  • 实际发布的 EXE / DLL 版本
  • 该版本对应的 PDB
  • 是从哪个 commit / 哪条 build pipeline 产出的
  • 安装包与发布物的版本信息

8.2 要输出到哪里、保留几份

full dump 会相当大,一开始就先定:

  • 不要放在系统盘根目录
  • 划到专用文件夹
  • DumpCount-n 设上限
  • 长期保存与临时保存分开

8.3 谁可以看这些 dump

full dump 有可能混入敏感或个人信息:

  • 明文配置
  • 连接字符串
  • token 或凭证
  • 崩溃前正在处理的业务数据
  • 文件路径或用户名

所以 「抓什么」的设计,要与「谁可以接触」一起定

9. 拿到 dump 后的最短分析路线

拿到 dump 之后要做的事其实很朴实:

9.1 安装 WinDbg

现在可从 Microsoft Store 或 winget 安装。

winget install Microsoft.WinDbg

9.2 打开 dump

windbg -z C:\CrashDumps\MyApp\MyApp_YYMMDD_HHMMSS.dmp

9.3 设置符号

先接通 Microsoft 公开符号,再把自己的 PDB 路径加进去。

.symfix C:\Symbols\Microsoft
.sympath+ C:\Symbols\MyApp
.reload

9.4 先看自动分析

!analyze -v

之后依序看:

  • 是哪个异常代码
  • faulting module 是什么
  • 自己的代码在堆栈上露到哪
  • 除了异常 thread,其他 thread 有没有奇怪的等待或卡住

10. 常见踩坑

10.1 dump 有了,但 PDB 没了

这种情况不少。dump 有抓到,但没有符号就读得很片段。
配置 dump 的同一时间,就把 PDB 的保存设计一起做

10.2 没检查 DumpFolder 的 ACL

在服务或已做权限隔离的进程上,这里很容易空转。
先确认「那个进程真的能写进去吗」

10.3 持续把 full dump 往正式环境的系统盘写

这是容量事故的常客。
保留份数限制与输出位置分离,一开始就要配置好。

10.4 想用 WER 一手包 hang 的情境

WER LocalDumps 主要对 crash 有效。
hang 或 first chance exception,ProcDump 有些情境更合适

10.5 永远开着 -e 1,被异常洪流淹没

first chance exception 很好用,但数量就是多。
设份数上限、短时间才开、限缩目标 才实务。

11. 总结

在复现率低的故障场景里,crash dump 是相当有力的观测点。特别是 Windows 应用牵涉 COM、P/Invoke、原生 DLL、或长时间运行时,一开始就先把「崩溃后要留下什么」定清楚,非常值得。

推荐的顺序很单纯:

  1. 先把 WER LocalDumps 按应用单独配置好
  2. 必要时再加 ProcDump
  3. 想进一步控制,再以独立进程为前提使用 MiniDumpWriteDump

按这个顺序走,比较不会走偏。

12. 参考资料

共享相同标签的最新文章。可以围绕相近的主题进一步加深理解。

伪随机数与真随机数的区别 - 如何区分的整理

本文整理伪随机数与真随机数的区别,重点不在输出外观而在生成器结构:普通 PRNG 重视可重现性、CSPRNG / DRBG 主打不可预测性、NRBG 则以物理熵源为基础。文中说明种子(seed)与重新播种(reseed)、健康检测(health test)的作用,并给出信息...

常见问题

汇总了咨询这一主题时常见的问题。

Crash dump 是什么?能看到哪些信息?
Crash dump 是在应用崩溃当下,把进程状态存成文件的快照,比起监控录像更像事故现场的静止画面。从 dump 通常能读到异常代码、挂掉那条 thread 的调用堆栈、当时加载的模块,依包含的内存多寡还能看到 heap 的状态与对象内容。但走到崩溃前的时序、和通信或设备之间的外部状态,光靠 dump 就比较不够,实务上要搭配日志与 heartbeat 一起使用。
WER LocalDumps 要怎么配置?
在注册表 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\Windows Error Reporting\LocalDumps 下,建议按应用单独创建子键(例如 MyApp.exe),设置三个值:DumpFolder 指定 dump 的输出位置(划一个专用文件夹)、DumpCount 设保留份数(从 5〜10 起)、DumpType 选 dump 种类(1 为 mini、2 为 full,起手式先用 2)。设置完成后,一定要先在验证环境亲自触发一次 crash,确认 .dmp 有出现在预期文件夹且能用 WinDbg 打开。
WER 和 ProcDump 该怎么分工?
先按应用单独配置 WER LocalDumps 是最稳妥的起手式,不用额外部署工具就能在 crash 后把 dump 留在本地。ProcDump 则适合 WER 不好处理的情境:不想常设注册表项、要看 first chance exception、要抓 hang、或想用其他条件触发。自研收集用 MiniDumpWriteDump 放到最后再想就好。顺序是先 WER、再 ProcDump、最后自研,反过来做设计通常会变重。
该选 mini dump 还是 full dump?
开发机或验证机直接用 full dump;客户环境依容量与敏感度要求选 mini 或 full。怀疑是内存损坏、原生 DLL、COM、P/Invoke、或长时间运行后的状态异常时偏向 full。要注意 full dump 文件大,而且可能混入明文配置、连接字符串、token 等敏感信息,所以保存位置、保留份数、访问权限、分享流程要先定好。另外与 dump 同等重要的是 PDB 与发布 binary 的保存,没有符号能读到的信息会大幅减少。

作者简介

本文作者的个人简介页面。

Go Komura

小村软件有限公司 代表

以 Windows 软件开发、技术咨询与故障排查为中心,擅长难以复现的故障调查,以及既有资产仍在运行的项目。

返回博客列表