记录一次windbg分析WPF(.Net Framework)程序CPU异常的过程
一、背景:
运行在用户电脑的程序经过长时间运行后,CPU居高不下,经过网上查找学习资料后,终于搞定问题。希望借助本文能强化记忆。
备注:调试分析程序框架:.Net Framework 4.7.2
二、实施过程
1. 软件准备
1.1 安装windbg 软件。windbg 有两种方式安装,一是通过Windows 驱动程序工具包 (WDK)安装,二是通过windows应用商店安装。因为windbg需要按照程序平台(x86/x64)来选择版本使用,故推荐WDK方式安装。
WDK安装:下载 Windows 驱动程序工具包 (WDK) - Windows drivers | Microsoft Learn
应用商店安装:安装 WinDbg - Windows drivers | Microsoft Learn
2. 任务管理器导出异常程序DUMP文件
2.1 获取异常程序平台/体系结构(x86/x64)。打开任务管理器,在详细信息中查看异常程序的平台(win11叫体系结构)。
如下图,该程序体系结构为“x86”;
2.2 根据异常程序所在windows系统的版本和异常程序的平台重新启动任务管理器。
windows 32位系统:C:\Windows\System32\Taskmgr.exe
Windows 64位系统:
x86 程序:C:\Windows\SysWOW64\Taskmgr.exe
x64 程序:C:\Windows\System32\Taskmgr.exe
ps:在64位电脑运行x86程序时,如果使用默认的任务管理器导出dump文件将导致windbg无法分析。
2.3 在任务管理器中选中异常程序,通过右键菜单中的“创建转储文件”生成dump文件。生成dump文件后,会提示用户dump文件的存储位置。
3. 设置windbg符号文件路径
3.1 在电脑本地创建文件夹 D:\MySymbols,用于缓存从 micrsoft 下载的符号文件。
3.2 按照异常程序的平台打开windbg(一定要对应上),在 File - Symbol File Path的对话框中输入如下符号文件路径。
#目录D:\MySymbols可按实际路径调整
srv*D:\MySymbols;srv*https://msdl.microsoft.com/download/symbols;
详细符号文件设置方法参考:Windows 调试器的符号路径 - Windows drivers | Microsoft Learn
4. Windbg打开dump文件分析
4.1 将2.3 步骤生成的dump文件拖入windbg,windbg会打印上一步的符号文件路径信息。
4.2 windbg不能直接调试托管程序,需要SOS 调试扩展 (SOS.dll) 通过提供有关内部公共语言运行时 (CLR) 环境的信息。 SOS.dll 自动随 .NET Framework 一起安装。详细信息参考:SOS.dll(SOS 调试扩展) - .NET Framework | Microsoft Learn。自动加载CLR环境的方法如下,需要在command窗口输入命令然后回车:
.cordll -ve -u -l
.
备注:1)大部分文章介绍通过.loadby sos clr或者.load /path/to/sos.dll 命令加载CLR环境,实际操作均加载失败。2)加载失败需要确认windbg的版本、导出dump的任务管理是否用错,还有是否安装了 .NET Framework 环境。
4.3 使用命令!runaway查看每个线程消耗的时间信息。冒号前的数字为线程ID,通过每个线程消耗的时间可以知道哪个线程占用大量cpu。
4.4 使用命令 ~{线程ID}s 切换windbg当前调试线程。例如~6s。
4.5 使用命令 !clrstack 查看托管代码的堆栈跟踪。通过堆栈可知该线程当前执行的代码逻辑,从而确认异常点。
三、总结
本次定位异常的思路是先确认哪个工作线程占用大量的CPU时间片,然后通过查看该线程的堆栈确认代码文件和行数。如果有更好的思路,欢迎交流学习,谢谢!!
另外,截图的程序非实际分析程序,仅用于记录本次学习过程。
参考资料:
Microsoft Learn:培养开拓职业生涯新机遇的技能
无法查看.NET Framework 1.1的dump文件? - 中道学友 - 博客园 (cnblogs.com)
基于.NET框架版本在Windbg中加载sos的脚本 - 活着的虫子 - 博客园 (cnblogs.com)
windbg调试系列教程:sos扩展的介绍和使用 - 不忘初心BBQ - 博客园 (cnblogs.com)