如果您尝试调试代码,未优化的代码更容易调试。 优化代码后,编译器和运行时会更改发出的 CPU 代码,使其运行速度更快,但与原始源代码的直接映射较少。 如果映射不太直接,调试器通常无法告诉你局部变量的值,并且代码单步执行和断点可能无法按预期工作。
注释
有关 JIT(即时)调试的详细信息,请参阅 在 Visual Studio 中使用即时调试器进行调试。
优化在 .NET 中的工作原理
通常,发布生成配置会创建优化的代码,调试生成配置不会。
Optimize MSBuild 属性控制编译器是否被告知优化代码。
在 .NET 生态系统中,代码在两步过程中从源转换为 CPU 指令:首先,C# 编译器将键入的文本转换为名为 MSIL 的中间二进制形式,并将 MSIL 输出到 .dll 文件。 稍后,.NET 运行时将此 MSIL 转换为 CPU 指令。 这两个步骤都可以优化到某种程度,但 .NET 运行时执行的第二个步骤会执行更显著的优化。
“取消模块加载上的 JIT 优化(仅限托管)”选项
调试器提供了一个选项,用于控制启用优化编译的 DLL 加载到目标进程时会发生什么情况。 如果未选中此选项(默认状态),则当 .NET 运行时将 MSIL 代码编译为 CPU 代码时,它将保持启用优化。 如果选中了此选项,调试器将请求禁用优化。
在工具>窗格中的所有设置>>部分中可以配置禁止 JIT 优化(仅限托管)的模块加载选项:
可以在“工具”>对话框的“常规”>部分中配置“加载模块时禁止 JIT 优化(仅限托管)”选项:
何时应检查“取消 JIT 优化”选项?
从另一个源(例如 NuGet 包)下载 DLL 后,如果您想调试此 DLL 中的代码,请选中该选项。 为了使抑制功能正常工作,同时需要查找此 DLL 的符号 .pdb 文件。
如果只对在本地生成的代码进行调试感兴趣,最好将此选项保留为未选中状态,在某些情况下,启用此选项会显著降低调试速度。 速度放缓有两个原因:
- 优化的代码运行速度更快。 如果要关闭大量代码的优化,性能影响可能会增加。
- 如果已启用“仅我的代码”,调试器甚至不会尝试加载已优化的 DLL 的符号。 查找符号可能需要很长时间。
“禁止 JIT 优化”选项的限制
在以下两种情况下,启用此选项 不起作用 :
- 如果将调试器附加到正在运行的进程,此选项对附加调试器时已加载的模块没有影响。
此选项不会影响预编译的 DLL(或 ngen'ed)到本机代码。 但是,可以通过将环境变量“COMPlus_ReadyToRun”设置为“0”启动进程来禁用预编译代码的使用。 此方法告知 .NET Core 运行时禁用预编译映像的使用,这会强制运行时使用 JIT 编译框架代码。
如果要面向 .NET Framework,请添加环境变量 “COMPlus_ZapDisable” 并将其设置为 “1”。
将 "COMPlus_ReadyToRun": "0" 添加到 属性\launchSettings.js上的 文件中的每个配置文件,以进行设置:
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:59694/",
"sslPort": 44320
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"COMPlus_ReadyToRun": "0"
}
},
"HttpLoggingSample": {
"commandName": "Project",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"COMPlus_ReadyToRun": "0"
},
"applicationUrl": "https://localhost:5001;http://localhost:5000"
}
}
}