使用托管调试助手诊断错误
托管调试助手 (MDA) 是调试辅助程序,它与公共语言运行时 (CLR) 一起工作以提供关于运行时状态的信息。 这些助手生成关于无法通过其他方式捕获的运行时事件的信息性消息。 可以使用 MDA 隔离在托管代码和非托管代码之间转换时发生的难以发现的应用程序 Bug。 可通过向 Windows 注册表添加注册表项或设置环境变量,启用或禁用所有的 MDA。 可使用应用程序配置设置来启用特定 MDA。 可以在应用程序的配置文件中为某些单独的 MDA 设置附加配置设置。 由于将在加载运行时时分析这些配置文件,因此必须在托管应用程序启动之前启用 MDA。 不能为已经启动的应用程序启用 MDA。
注意 |
---|
启用 MDA 后,即使不在调试器下执行代码,MDA 也会处于活动状态。如果在调试器不存在时引发 MDA 事件,尽管这不是未经处理的异常,事件消息也会出现在未经处理的异常对话框中。若要避免出现该对话框,请在调试环境中未执行代码时移除 MDA 启用设置。 |
注意 |
---|
在 Visual Studio 集成开发环境 (IDE) 中执行代码时,可以避免针对特定 MDA 事件出现的异常对话框。为此,请在“调试”菜单上单击“异常”。(如果“调试”菜单不包含“异常”命令,请在“工具”菜单上单击“自定义”添加该命令。)在“异常”对话框中,展开“托管调试助手”列表,然后清除相应 MDA 的“引发”复选框。例如,若要避免出现 contextSwitchDeadlock MDA 的异常对话框,请在“托管调试助手”列表中清除该 MDA 名称旁边的“引发”复选框。也可以使用此对话框启用 MDA。 |
下表列出 .NET Framework 附带的 MDA。
默认情况下,.NET Framework 会为所有托管调试器激活 MDA 的子集。 通过单击**“调试”菜单上的“异常”并展开“托管调试助手”**列表可以查看 Visual Studio 中的默认集合。
启用和禁用 MDA
可使用注册表项、环境变量和应用程序配置设置,启用和禁用 MDA。 若要使用应用程序配置设置,就必须启用注册表项或环境变量。
在 Visual Studio 2005 和更高版本中,启用宿主进程后,不能禁用默认集合中的 MDA 或启用不在默认集合中的 MDA。 宿主进程是默认启用的,因此必须将其显式禁用。
若要在 Visual Studio 中禁用宿主进程,请执行下列操作:
在**“解决方案资源管理器”**中选择一个项目。
在**“项目”菜单上,单击“属性”**。
出现**“项目设计器”**窗口。
单击**“调试”**选项卡。
在**“启用调试器”部分中,清除“启用 Visual Studio 宿主进程”**复选框。
但是,禁用宿主进程会影响性能。 通过阻止 Visual Studio 在收到 MDA 通知时显示 MDA 对话框,可以无需禁用 MDA。 为此,请单击**“调试”菜单上的“异常”,展开“托管调试助手”列表,然后为单个 MDA 选中或清除“引发”**复选框。
使用注册表项启用和禁用 MDA
可通过在 Windows 注册表中添加 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\MDA 子项(类型为 REG_SZ,值为 1)启用 MDA。 将下面的示例复制到一个名为 MDAEnable.reg 的文本文件中,然后在 Windows 资源管理器中双击该文件名以在计算机上启用 MDA。
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework]
"MDA"="1"
若要禁用 MDA,请使用 Windows 注册表编辑器将 MDA 子项设置为 0(零)。 或者,可以将下面的示例复制到一个名为 MDADisable.reg 的文本文件中,然后在 Windows 资源管理器中双击该文件名。
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework]
"MDA"="0"
默认情况下,即使未添加该注册表项,有些 MDA 也会在运行附加到调试器的应用程序时启用。 pInvokeStackImbalance MDA 和 invalidApartmentStateChange MDA 即属于此类助手。 可以按本节前面所述运行 MDADisable.reg 文件来禁用这些助手。
使用环境变量启用和禁用 MDA
还可以通过环境变量 COMPLUS_MDA 控制 MDA 激活,此变量将重写注册表项。 COMPLUS_MDA 字符串是一个区分大小写的分号分隔的 MDA 名称列表或其他特殊控制字符串。 在托管或非托管调试器下启动将默认启用一组 MDA。 这是通过在环境变量或注册表项的值前面隐式附加默认在调试器下启用的分号分隔的 MDA 的列表来实现的。 特殊控制字符串如下:
0 - 停用所有 MDA。
1 - 从应用程序名称.mda.config 读取 MDA 设置。
managedDebugger - 显式激活在调试器下启动托管可执行文件时隐式激活的所有 MDA。
unmanagedDebugger - 显式激活在调试器下启动非托管可执行文件时隐式激活的所有 MDA。
如果存在冲突的设置,则最新的设置重写先前的设置:
COMPLUS_MDA=0 禁用所有 MDA,包括在调试器下隐式启用的那些 MDA。
COMPLUS_MDA=gcUnmanagedToManaged 启用 gcUnmanagedToManaged 以及在调试器下隐式启用的任何 MDA。
COMPLUS_MDA=0;gcUnmanagedToManaged 启用 gcUnmanagedToManaged,但是禁用将在调试器下隐式启用的 MDA。
使用特定于应用程序的配置设置启用和禁用 MDA
可以在应用程序的 MDA 配置文件中单独地启用、禁用和配置某些助手。 若要使用用于配置 MDA 的应用程序配置文件,则必须设置 MDA 注册表项或 COMPLUS_MDA 环境变量。 应用程序配置文件通常与应用程序的可执行文件 (.exe) 位于同一目录中。 文件名采用“应用程序名称.mda.config”形式;例如,notepad.exe.mda.config。 在应用程序配置文件中启用的助手可能包含专门设计用于控制该助手的行为的特性或元素。 下面的示例演示如何启用和配置封送 MDA。
<mdaConfig>
<assistants>
<marshaling>
<methodFilter>
<match name="*"/>
</methodFilter>
<fieldFilter>
<match name="*"/>
</fieldFilter>
</marshaling>
</assistants>
</mdaConfig>
对于应用程序中每个托管到非托管的转换,Marshaling MDA 会发出有关正在被封送处理为非托管类型的托管类型的信息。 Marshaling MDA 还能够分别筛选 <methodFilter> 和 <fieldFilter> 子元素中提供的方法和结构字段的名称。
下面的示例演示如何使用其默认设置来启用多个 MDA。
<mdaConfig>
<assistants>
<illegalPrepareConstrainedRegion />
<invalidCERCall />
<openGenericCERCall />
<virtualCERCall />
</assistants>
</mdaConfig>
重要事项 |
---|
若在配置文件中指定了多个助手,则必须按字母顺序列出这些助手。例如,若要同时启用 virtualCERCall 和 invalidCERCall MDA,则必须先添加 <invalidCERCall /> 项,再添加 <virtualCERCall /> 项。如果这些项未按字母顺序排列,则将显示未处理的无效配置文件异常消息。 |
MDA 输出
MDA 输出类似于下面的示例,此示例显示了来自 pInvokeStackImbalance MDA 的输出。
A call to PInvoke function 'MDATest!MDATest.Program::StdCall' has unbalanced the stack. This is likely because the managed PInvoke signature does not match the unmanaged target signature. Check that the calling convention and parameters of the PInvoke signature match the target unmanaged signature.