我曾看到过许多开发人员使用错误的工具来分析问题,更有甚者,有些人连任何工具都没有使用。他们采取的分析方法通常包括:输出更多的调试信息,或者做一些临时性的代码审查。这里的临时性是指,通过猜测来推断问题可能来之哪个部分的代码。有时候,开发人员会幸运的发现问题刚好处于他们正在审查的代码当中。然而,在更多情况下并非如此,问题发生的位置和表现出来的位置往往相差甚远。说起来有点可笑,我很长一段时间都是这样调试的。自从我接触了《Net 高级调试》,调试原来不是这样的。通过使用一些功能强大的调试工具,开发人员可以极大的减少在分析问题时耗费的时间。
所以,我们必须学会如何使用工具进行调试,要知道每种工具在哪些情况下使用以及如何使用。这是对大家的建议,更多是对我自己的鞭策。今天我们就介绍一些调试中经常要用到的一些工具。
在开始之前,我还得说明一下,《Net 高级调试》这本书,写的挺早的,中文翻译的版本是2011年机械工业出版社出版的,里面的内容有些也比较老旧,我都做了实时的更新,都是最新的。因为这次只是工具介绍,具体的环境就不做说明了。还有,有些工具,比如:NTSD、KD等类似的命令行调试器我就不太在行了,所以我会使用在这个系列出现的GUI调试工具(Windbg)来调试问题,具体其他调试器使用方法,大家可以自行补充。
二、常用调试工具
我们想要成为高级程序员,高级的调试技巧必须掌握,当然,这些技巧需要借助工具来体现,我们下面就来介绍一下将在我这个系列里面用到的一些调试工具,当前不是全部,我会在以后得章节里,有需要在介绍一些用到的调试工具。
说起调试工具,其实有很多,他们的用途也不一样,有一部分工具侧重分析某一类特定的问题,而有些工具可以同时处理若干类问题,我们要知道每种工具在什么情况下使用以及如何使用,这一点非常重要。
1、Windows 调试工具集
Windows 调试工具集是一个免费的软件包,它有两个版本:32位和64位。在这个工具集中有3种用户态调试工具:NTSD(Microsoft NT 符号调试器)、CDB(Microsoft 控制台调试器) 和 WinDbg,以及一种内核态调试器 KD。我说一下区别:NTSD 和 CDB(KD 它属于内核态调试器,但是它是命令行调试器)都是命令行调试器,Windbug 是一个具有界面的调试器,它可以更容易调试源代码。他们虽然有这些区别,但是他们使用了相同的内核调试器引擎。
【应用场合】一组调试器和调试工具。
【下载地址】https://learn.microsoft.com/zh-cn/windows-hardware/drivers/debugger/debugger-download-tools
【软件版本】Microsoft (R) Windows Debugger Version 10.0.22621.2428(书上:6.8.4.0)
Windebug效果如图:
NTSD如图:
我们安装了调试器工具集,也要配置环境变量,就不用每次使用都切换目录。
可以将 Windows 调试工具作为开发工具包的一部分或独立工具集获取:a、作为 WDK 的一部分
Windows 调试工具包含在 Windows 驱动程序工具包 (WDK) 中。 若要获取 WDK,请参阅下载 Windows 驱动程序工具包 (WDK)。
b、作为 Windows SDK 的一部分
Windows 调试工具包含在 Windows 软件开发工具包 (SDK) 中。 若要下载安装程序或 ISO 映像,请参阅 Windows 开发人员中心上的 Windows SDK。
c、作为独立工具集
你可以单独安装适用于 Windows 的调试工具,而无需 Windows SDK 或 WDK,方法是开始安装 Windows SDK,然后在功能列表中选择“ Windows 调试工具” 以安装 (并清除) 选择所有其他功能。 若要下载安装程序或 ISO 映像,请参阅 Windows 开发人员中心上的 Windows SDK。
我使用的Windows SDK 版本的安装,Windows SDK (10.0.22621) for Windows 11,版本 22H2 (2023 年 10 月更新) 提供了用于生成 Windows 应用程序的最新标头、库、元数据和工具。 使用此 SDK 为Windows 11版本 22H2 和早期 Windows 版本生成通用 Windows 平台 (UWP) 和 Win32 应用程序。
Windows SDK 官网下载地址:https://developer.microsoft.com/zh-cn/windows/downloads/windows-sdk/
2、Net 8.0 可再发行组件和 Net 8.0 SDK
刚开始说起【可再发行组件】,我是一头懵,不知道是什么。知道了是什么东西,也很容易,只是我们不这样说,叫它“可再发行组件”。【Net 8.0 可再发行组件】就是 Net 8.0 Runtime 运行时的组件。
【应用场合】Net 运行时(.Net Runtime)
【下载地址】https://dotnet.microsoft.com/zh-cn/download/dotnet/8.0
【组件版本】8.0(书上是:2.0)
点击下载地址,我们就可以进入下载页面,当然,随着时间的推移,这个版本也是会发生变化的。这个页面左侧是 Net 8.0 SDK ,右侧页面就是各种的 Runtime,有我们经常用于运行 Web 页面:ASP.NET Core 运行时 8.0.0,运行桌面程序的:NET 桌面运行时 8.0.0,等等很多。
运行时和SDK 的区别就是,【运行时】就是一个Net 运行基础的、必须的环境,很干净,包括所有的框架程序集以及 Net 运行时的二进制文件,一点多余的东西都没有。
SDK 是包含【运行时】的全部功能,只有SDK 才能使开发人员编写新的 Net 应用程序,因为它提供了所有必要的工具(编译器、汇编器、构建工具)及其库等。Net SDK 并不提供基于图形界面的集成开发环境,而只是提供了一个基于命令行的环境。我们一般选择在服务器上安装更干净的【运行时】,在开发平台选择安装 SDK。
效果如图:
3、SOS
SOS名称的来历:SOS 不是求救的意思,当 Net 框架哈仔 1.0 阶段时,Microsoft 团队使用了一个叫【STRIKE】的调试器扩展来分析 Net 代码中的各种复杂问题。当 Net 框架日趋成熟时,这个调试器扩展的名称也就逐渐演变成了“Son of Strike”(SOS)。
用于调试 Net 应用程序的扩展组件。SOS 是一个调试器扩展,用于调试 Net 应用程序,它提供了一组非常丰富的命令,这些命令使开发人员可以对 CLR进行深入分析,并且有助于找出应用程序中各种复杂错误的原因。当然,它还有一些命令可以用来查看【终结队列】、【托管堆】、【托管线程】,在托管代码中设置断点以及查看异常等。
由于SOS 能够提供 CLR 内部工作机制的抽象视图,因此在使用SOS济宁调试时,必须使用正确版本的SOS。每个版本的 Net 在发布时都带有相应的SOS,可以在以下位置找到:
%windir%\Microsoft.NET\<architecture>\<version>\sos.dll
architecture:可以是 Framework(32位)或者 Framework(64位),而 version 可以表示所使用的 Net 框架的版本。
C:\Windows\Microsoft.NET\Framework\v4.0.30319\
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\
32位 SOS 效果如图:
64位 SOS 效果如图:
Windbg Preview 是不用单独执行加载的工作的,它会自动加载它所需要的版本,如果是老版本的 Windbg,比如:windbg10 ,可以通过 .load 命令加载 SOS.dll。一般情况,使用windbg自带的命令【.load sos】即可自动加载,使用【.chain】查看加载是否成功。
我们执行【.chain】命令,看一下执行效果,说明一下,要想执行这个命令,我们要创建一个项目,通过 Windbg 加载我们的 EXE 项目,通过【g】命令运行程序,就可以执行命令了,否则看不到 SOS。效果如图:
4、SOSEX
我们在上面说了SOS.DLL,这里我们在说说 SOSEX.DLL,它也是用于调试 Net 应用程序的扩展组件,可以用于非托管代码和托管代码的调试,他是有 Steve Johnson 开发的,SOSEX表示SOS Extended。SOSEX 增加了一组功能强大的调试命令,这些命令包含【死锁检测】、基于代的垃圾收集命令以及其他一些功能强大的断点命令。
SOSEX的安装包只是一个ZIP文件,只需将 ZIP文件中压缩的文件释放到指定为止即可完成安装。但是需要说明一下,它虽然很强大,但是只能在 Net Framework 平台上使用,我们最新的跨平台是不能使用的。太可惜了。
如果大家需要调试 Net Framework 版本的程序,它还是很有用的,大家可以去网上自行下载。
我的下载地址:https://www.xiazaila.com/soft/46338.html我先给大家一个印象吧,有一个直观的感觉,截图如下:
5、CLR分析器
CLR 分析器:堆内存分配情况进行分析。在调试 Net 应用程序中与内存相关的问题时,CLR分析器是一种非常有用的工具。它可以提供的功能:堆的统计信息、垃圾收集操作的统计信息、垃圾收集器句柄统计信息、垃圾收集中每代对象的总体大小、性能分析的统计信息。
CLR分析器的安装过程很简单,安装包是一个 ZIP文件,只需将 ZIP 文件的内容释放到指定的文件夹即可完成安装。它也是分为两个版本:32位的和64位的,要启动 CLR 分析器,只需运行 CLRProfiler.exe,效果如图:
运行效果如图:
官网下载地址:https://github.com/microsoftarchive/clrprofiler/releases
6、性能计数器
在安装 Net 框架的同时会安装一组性能计数器,我们可以通过 Windows 性能监视器(Windows Performance Monitor)来查看这些性能计数器。这些性能计数器包含:
异常(.NET CLR Exceptions):与 Net 应用程序中抛出的异常相关的性能计数器。
互用性(NET CLR Interop):与 Net 应用程序中对 COM,COM+以及外部库等使用情况相关的性能计数器。
即时编译(NET CLR Jit):与 即时编译【JIT】相关的性能计数器。
加载器(NET CLR Loading):与加载 Net 各种实体【例如程序集,类型等】相关的性能计数器。
锁和线程(NET CLR LocksAndThreads):与线程以及锁定行为相关的性能计数器。
内存(NET CLR Memory):与垃圾收集器和内存使用相关的性能计数器。
网络(NET CLR Networking/NET CLR Networking 4.0.0.0):与 Net 应用程序在网络上的发送和接受等操作相关的性能计数器。
远程行为(NET CLR Remoting):与 Net 应用程序中的远程对象相关的性能计数器。
安全(NET CLR Security):与 Net 框架执行的安全检查相关的性能计数器。
我们可以在开始菜单里面找到他们,依次【Windows 管理工具】---》【性能监视器】,效果如图:
我们打开【性能监视器】,操作界面如下:
我们可以点击绿色的加号,就能看到性能计数器的类别,如图:
7、Net 反编译器
如果我们想查看已经编译后文件的源代码,怎么办呢?立刻我们就会想到反编译工具,这种编译器可以从 MSIL中生成各种高级语言代码。这种工具不少,比如以前用的比较多的 Reflector.exe,但是,相对于现在来说还是使用感觉比较差。我在这里推荐 ILSpy和 DnSpy,他们两个都可以查看元数据、IL代码,不同点就是 DnSpy 可以像 Visual Studio 那样编辑和调试代码,功能很强大。
【应用场合】ILSpy 可以反编译源码,DnSpy 可以反编译源码和调试源码。
【下载地址】ILSpy官网下载地址:https://github.com/icsharpcode/ILSpy
DnSpy官网下载地址:https://github.com/dnSpy/dnSpy
【软件版本】ILSpy 版本:7.2.1.6856,DnSpy 版本:6.1.8.0
ILSpy 操作界面截图如下:
DnSpy操作界面截图如下:
8、PowerDbg
PowerDbg 是由 Roberto Farah 开发的一个库,它使开发人员通过 Powershell 来控制非托管调试器。当希望通过命令行来控制调试器的运行时,它是一个非常有用的工具,易于扩展,并且能够对常用的命令进行调用和格式化。
PowerDbg的工作原理是向运行中的 WinDbg 发送各种命令,任何命令在执行时,将首先打开一个日志文件,接下来在执行命令,最后关闭日志文件。PowerDbg 脚本通过这个日志文件来分析结果和产生输出信息。
我个人不太推荐,使用繁琐,全部是命令行,不是所见即所得的,不方便实用,还是不如直接使用 Windbg 来的更快,如果大家想试试的,也是个好事。
官网下载地址:https://www.softpedia.com/get/Programming/Components-Libraries/PowerDbg.shtml
9、托管调试助手
托管调试助手(MDA)用于一般性的 CLR 调试,它并不是一个独立的工具,而是 CLR 中的一个组件,在运行和调试 Net 应用程序是将提供各种有用的信息。通过对【运行时】加你选哪个监测,可以找出一些常见的编程错误并且能在发布应用程序之前修复它们。MDA 可以分为几类:
非托管互用性:与非托管互用性问题相关的调试助手。
非托管互用性(COM):与 COM 非托管互操作问题相关的调试助手。
非托管互用性(P/Invoke):与平台调用非托管互用性问题相关的调试助手。
加载器:CLR 加载器相关的调试助手。
线程:与线程问题相关的调试助手。
BCL:与基础类库问题相关的调试助手。
其他:其他调试问题。
如果大家想了解 MDA 更多的内容,可以直接去微软的网站上去查看。以下是网址:https://learn.microsoft.com/zh-cn/dotnet/framework/debug-trace-profile/diagnosing-errors-with-managed-debugging-assistants。这里面说的很清楚,直接学习就可以了。
三、总结
新的开始,新的征程。我从今天开始要写一个新的系列,这个系列完全是按着《Advanced .Net Debugging》这本书的节奏和章节来的,当然了,有的内容过于老旧还是会有所删减,但是质量不会降低。我写完上一个高级调试的系列,收货还是挺丰富的。那个系列可以带我入门,如果想真的有所提升,还是需要将整本书重新研读。估计这个系列的路也不一定好走,还好我喜欢编程,喜欢知其然,也要做到知其所以然,有这样的决心支持我走下去。不忘初心,继续努力吧。