使用托管调试助手诊断错误

注释

本文特定于 .NET Framework。 它不适用于 .NET 的较新版本实现,包括 .NET 6 及更高版本。

托管调试助手(MDA)是调试辅助工具,可配合公共语言运行时(CLR)提供有关运行时状态的信息。 这些助手可生成关于你无法通过其他方式捕获的运行时事件的信息性消息。 可以使用 MDAs 来隔离在托管代码和非托管代码之间转换时发生的难以查找的应用程序错误。

可以通过向 Windows 注册表添加密钥或通过设置环境变量 来启用或禁用 所有 MDA。 可以使用应用程序配置设置启用特定的 MDA。 可以在应用程序的配置文件中为某些单独的 MDA 设置其他配置设置。 由于加载运行时时会分析这些配置文件,因此必须在托管应用程序启动之前启用 MDA。 不能为已启动的应用程序启用它。

下表列出了随 .NET Framework 一起附带的 MDA:

MDA
asynchronousThreadAbort
绑定失败
callbackOnCollectedDelegate
contextSwitchDeadlock
危险线程API
dateTimeInvalidLocalFormat
dirtyCastAndCallOnInterface
disconnectedContext
dllMainReturnsFalse
exceptionSwallowedOnCallFromCom
failedQI
fatalExecutionEngineError(致命执行引擎错误)
gcManagedToUnmanaged
gcUnmanagedToManaged
illegalPrepareConstrainedRegion
invalidApartmentStateChange(无效的公寓状态更改)
invalidCERCall
invalidFunctionPointerInDelegate
invalidGCHandleCookie
invalidIUnknown
无效成员声明
invalidOverlappedToPinvoke
无效变体
jitCompilationStart
loaderLock
loadFromContext
marshalCleanupError
编组
成员信息缓存创建
moduloObjectHashcode
nonComVisibleBaseClass
notMarshalable
openGenericCERCall
overlappedFreeError
pInvokeLog
pInvokeStackImbalance
raceOnRCWCleanup
reentrancy
releaseHandleFailed
reportAvOnComRelease
流写器缓冲数据丢失
virtualCERCall

默认状态下,.NET Framework 为所有托管调试器激活一组 MDA 子集。 可以通过选择“调试”菜单上的 >异常设置,然后展开“托管调试助手”列表,在 Visual Studio 中查看默认集。

Visual Studio 中的“异常设置”窗口

启用和禁用 MDA

可以使用注册表项、环境变量和应用程序配置设置来启用或禁用 MDA。 必须启用注册表项或环境变量才能使用应用程序配置设置。

小窍门

可以在收到 MDA 通知时阻止 Visual Studio 显示 MDA 对话框,而无需禁用 MDA。 为此,请在“调试”菜单上选择>异常设置”,展开“托管调试助手”列表,然后选择或清除单个 MDA 的“引发时中断”复选框。

注册表项

若要启用 MDA,请在 Windows 注册表中添加 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework\MDA 子项(类型REG_SZ,值 1)。 将以下示例复制到名为 MDAEnable.reg的文本文件中。打开 Windows 注册表编辑器(RegEdit.exe),然后从 “文件” 菜单中选择“ 导入”。 选择 MDAEnable.reg 文件以在该计算机上启用 MDA。 将子项设置为 字符串值 1 (而不是 DWORD 值 1)可让从 ApplicationName.suffix.mda.config 文件中读取 MDA 设置。 例如,Notepad 的 MDA 配置文件将被命名为 notepad.exe.mda.config。

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework]
"MDA"="1"

如果计算机在 64 位作系统上运行 32 位应用程序,则应设置 MDA 密钥,如下所示:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework]
"MDA"="1"

有关详细信息 ,请参阅Application-Specific 配置设置 。 可以通过 COMPLUS_MDA 环境变量覆盖注册表设置。 有关详细信息,请参阅 环境变量

若要禁用 MDA,请使用 Windows 注册表编辑器将 MDA 子项设置为 0 (零)。

默认情况下,即使未添加该注册表项,有些 MDA 也会在运行附加到调试器的应用程序时启用。 可以通过运行本节前面所述的 MDADisable.reg 文件来禁用这些助手。

环境变量

MDA 激活也可以由环境变量控制,该变量 COMPLUS_MDA替代注册表项。 该 COMPLUS_MDA 字符串是 MDA 名称或其他特殊控制字符串的不区分大小写的分号分隔列表。 在托管或非托管调试器下启动程序时,默认启用一组 MDA。 这是通过在环境变量或注册表项的值前面,隐式附加默认在调试器下启用的、以分号分隔的 MDA 的列表来实现的。 特殊控制字符串如下:

  • 0 - 停用所有 MDA。

  • 1 - 从 ApplicationName.mda.config读取 MDA 设置。

  • managedDebugger - 显式激活在调试器下启动托管可执行文件时隐式激活的所有 MDA。

  • unmanagedDebugger - 显式激活在调试器下启动非托管可执行文件时隐式激活的所有 MDA。

如果存在冲突的设置,最新设置将替代以前的设置:

  • COMPLUS_MDA=0 禁用所有 MDA,包括调试器下隐式启用的 MDA。

  • 除了调试器下隐式启用的所有 MDA,COMPLUS_MDA=gcUnmanagedToManaged 还启用 gcUnmanagedToManaged

  • COMPLUS_MDA=0;gcUnmanagedToManaged 启用 gcUnmanagedToManaged,但是禁用将在调试器下隐式启用的 MDA。

特定于应用程序的配置设置

可以在应用程序的 MDA 配置文件中单独启用、禁用和配置某些助理。 若要启用应用程序配置文件来配置 MDA,必须设置 MDA 注册表项或 COMPLUS_MDA 环境变量。 应用程序配置文件通常与应用程序的可执行文件(.exe)文件位于同一目录中。 文件名采用 ApplicationName.mda.config形式;例如,notepad.exe.mda.config。在应用程序配置文件中启用的助手可能具有旨在控制该助手行为的属性或元素。

下面的示例演示如何启用和配置 marshaling

<mdaConfig>
  <assistants>
    <marshaling>
      <methodFilter>
        <match name="*"/>
      </methodFilter>
      <fieldFilter>
        <match name="*"/>
      </fieldFilter>
    </marshaling>
  </assistants>
</mdaConfig>

对于应用程序中每个托管到非托管的转换,Marshaling MDA 会发出有关正封送到非托管类型的托管类型信息。 Marshaling MDA 还可以分别筛选 methodFilterfieldFilter 子元素中提供的方法和结构字段的名称。

以下示例演示如何使用默认设置启用多个 MDA:

<mdaConfig>
  <assistants>
    <illegalPrepareConstrainedRegion />
    <invalidCERCall />
    <openGenericCERCall />
    <virtualCERCall />
  </assistants>
</mdaConfig>

重要

在配置文件中指定多个助手时,必须按字母顺序列出它们。 例如,如果要同时启用virtualCERCallinvalidCERCall这两个 MDA,则必须在添加<invalidCERCall />条目之前加入<virtualCERCall />条目。 如果条目不是按字母顺序排列的,则会显示未经处理的无效配置文件异常消息。

MDA 异常

启用 MDA 后,即使代码未在调试器下执行,它也处于活动状态。 如果调试器不存在时引发 MDA 事件,则事件消息会显示在未经处理的异常对话框中,尽管它不是未经处理的异常。 若要避免对话框,请在代码未在调试环境中执行时删除启用 MDA 的设置。

当代码在 Visual Studio 集成开发环境(IDE)中执行时,可以避免针对特定 MDA 事件显示的异常对话框。 为此,请在 “调试” 菜单上,选择 “Windows>异常设置”。 在 “异常设置” 窗口中,展开 “托管调试助手 ”列表,然后清除单个 MDA 的“ 引发时中断 ”复选框。 还可以使用此对话框 启用 MDA 异常对话框的显示。

MDA 输出

MDA 输出类似于以下示例,其中显示了 MDA 的 PInvokeStackImbalance 输出:

调用 PInvoke 函数 'MDATest!MDATest.Program::StdCall' 导致堆栈失衡。 这可能是因为托管 PInvoke 签名与非托管目标签名不匹配。 检查 PInvoke 签名的调用约定和参数是否与目标非托管签名匹配。

另请参阅