为什么我在调试时看不到堆栈中间的局部变量 ASP.NET 来自 Visual Studio 的核心源代码
Why I cannot see local variables in the middle of the stack while debugging ASP.NET Core source code from Visual Studio
我正在尝试通过调试基于 API 项目模板的“开箱即用”WeatherForecast 应用程序来探索 ASP.NET 核心管道。
根据各种资源,我在 VS 中设置了以下配置:
工具->选项->调试->常规
- 启用 .NET Framework 源步进 - 选中
- 启用源 Link 支持 - 选中
- 抑制模块加载时的 JIT 优化 - 选中
- 使用托管兼容模式(尝试了两种组合 checked/unchecked,但它似乎确实影响了任何东西)
工具->选项->调试->符号
- 加载所有模块,除非排除 - 选中
- 作为符号的位置,我尝试了 Microsoft 符号服务器和集成到 JetBrains dotPeek 中的符号服务器
项目属性->调试->环境变量
- COMPLUS_JITMinOpts = 1 [根据 https://github.com/dotnet/runtime/issues/5767]。事实上,我相信这就是 'Suppress JIT optimization on module load' 所做的。
- COMPLUS_ZapDisable = 1 [避免加载原生图片]
项目属性->构建
- 优化代码 - 未选中
当我启动调试器并转到 Debug->Windows->Modules 时,我可以看到所有 ASP.NET 核心 dll 都加载了符号并且优化列设置为 'No'.
但是,当我在控制器中遇到断点并遍历调用堆栈时,Locals window:
中出现了很多错误
'Cannot obtain value of the local variable or argument because it is not available at this instruction pointer, possibly because it has been optimized away'
我认为优化没有关闭,但我可以在 asp.net 源代码中的函数内部设置断点并观察局部变量。
当执行指针移动到不同的函数时,问题就出现了。一旦发生这种情况,这些局部变量将变得不可用。
在此线程 https://github.com/aspnet/Mvc/issues/8375 中,有人建议构建程序集的调试版本,但我无法完全理解为什么有必要这样做。
我的理解是编译器只是通过删除 NOP 指令和死代码块使 IL 代码更干净。真正的优化工作是由 JIT 完成的,可以通过 COMPLUS_JITMinOpts 和 COMPLUS_ZapDisable 标志来控制。
有没有办法在遍历堆栈时避免这些 'possibly because it has been optimized away' 消息?看来我在这里遗漏了一些重要的概念,但我不知道从哪里看。
我在 VS2019(核心 3.1)和 VS2017(核心 2.2)中得到了相同的行为
试试这些:
1) 不确定您还使用了哪些其他设置。为了给你更好的指导,我建议你可以先尝试在 Tools-->Import and Export Settings-- 下重置所有 vs 设置-- >重置所有设置 以避免其他被忽略的选项。
2)如果使用Release模式,请进入Project Properties--> 构建-->高级--> 将调试信息更改为Full
。使用与 Debug.
相同的模式
3) 请在项目 Properties 下取消选中 Optimize Code 复选框-->建造.
然后,在工具下选中抑制模块加载时的 JIT 优化(仅限托管) -->调试-->一般.
4) 删除 bin
和 obj
文件夹,然后再次重建您的项目。
更新 1
我的解决方案将使 Release 模式更接近 Debug 模式并且由于它仍然看不到局部变量,恐怕 Release 模式不能随心所欲地改变。
让我更详细地解释一下:
具体,Release模式不是为了调试而产生的,是最终产品最好的release,显然有如果您想查看代码中的堆栈和变量,可能会发生各种意外情况,这是真实的,所以我们不建议这样做。
在Debug模式下,pdb
文件很大,包含了你想要的所有调试类型,只有在debug模式下,你才能享受所有的调试类型。 debug模式用于调试项目,Release是在调试项目没有问题的情况下创建最终优化版本,以减少release,方便发布者分发程序。
结果,在Release模式下调试时,难免出问题
我的解决办法是让Release更接近Debug模式而且好像Release的根行为是不能改变的,所以只好用Debug模式观察局部变量而这种模式是为正式调试而设计的。你应该使用调试。
试一试
我正在尝试通过调试基于 API 项目模板的“开箱即用”WeatherForecast 应用程序来探索 ASP.NET 核心管道。
根据各种资源,我在 VS 中设置了以下配置:
工具->选项->调试->常规
- 启用 .NET Framework 源步进 - 选中
- 启用源 Link 支持 - 选中
- 抑制模块加载时的 JIT 优化 - 选中
- 使用托管兼容模式(尝试了两种组合 checked/unchecked,但它似乎确实影响了任何东西)
- 启用 .NET Framework 源步进 - 选中
工具->选项->调试->符号
- 加载所有模块,除非排除 - 选中
- 作为符号的位置,我尝试了 Microsoft 符号服务器和集成到 JetBrains dotPeek 中的符号服务器
- 加载所有模块,除非排除 - 选中
项目属性->调试->环境变量
- COMPLUS_JITMinOpts = 1 [根据 https://github.com/dotnet/runtime/issues/5767]。事实上,我相信这就是 'Suppress JIT optimization on module load' 所做的。
- COMPLUS_ZapDisable = 1 [避免加载原生图片]
- COMPLUS_JITMinOpts = 1 [根据 https://github.com/dotnet/runtime/issues/5767]。事实上,我相信这就是 'Suppress JIT optimization on module load' 所做的。
项目属性->构建
- 优化代码 - 未选中
- 优化代码 - 未选中
当我启动调试器并转到 Debug->Windows->Modules 时,我可以看到所有 ASP.NET 核心 dll 都加载了符号并且优化列设置为 'No'. 但是,当我在控制器中遇到断点并遍历调用堆栈时,Locals window:
中出现了很多错误'Cannot obtain value of the local variable or argument because it is not available at this instruction pointer, possibly because it has been optimized away'
我认为优化没有关闭,但我可以在 asp.net 源代码中的函数内部设置断点并观察局部变量。 当执行指针移动到不同的函数时,问题就出现了。一旦发生这种情况,这些局部变量将变得不可用。
在此线程 https://github.com/aspnet/Mvc/issues/8375 中,有人建议构建程序集的调试版本,但我无法完全理解为什么有必要这样做。 我的理解是编译器只是通过删除 NOP 指令和死代码块使 IL 代码更干净。真正的优化工作是由 JIT 完成的,可以通过 COMPLUS_JITMinOpts 和 COMPLUS_ZapDisable 标志来控制。
有没有办法在遍历堆栈时避免这些 'possibly because it has been optimized away' 消息?看来我在这里遗漏了一些重要的概念,但我不知道从哪里看。
我在 VS2019(核心 3.1)和 VS2017(核心 2.2)中得到了相同的行为
试试这些:
1) 不确定您还使用了哪些其他设置。为了给你更好的指导,我建议你可以先尝试在 Tools-->Import and Export Settings-- 下重置所有 vs 设置-- >重置所有设置 以避免其他被忽略的选项。
2)如果使用Release模式,请进入Project Properties--> 构建-->高级--> 将调试信息更改为Full
。使用与 Debug.
3) 请在项目 Properties 下取消选中 Optimize Code 复选框-->建造.
然后,在工具下选中抑制模块加载时的 JIT 优化(仅限托管) -->调试-->一般.
4) 删除 bin
和 obj
文件夹,然后再次重建您的项目。
更新 1
我的解决方案将使 Release 模式更接近 Debug 模式并且由于它仍然看不到局部变量,恐怕 Release 模式不能随心所欲地改变。
让我更详细地解释一下:
具体,Release模式不是为了调试而产生的,是最终产品最好的release,显然有如果您想查看代码中的堆栈和变量,可能会发生各种意外情况,这是真实的,所以我们不建议这样做。
在Debug模式下,pdb
文件很大,包含了你想要的所有调试类型,只有在debug模式下,你才能享受所有的调试类型。 debug模式用于调试项目,Release是在调试项目没有问题的情况下创建最终优化版本,以减少release,方便发布者分发程序。
结果,在Release模式下调试时,难免出问题
我的解决办法是让Release更接近Debug模式而且好像Release的根行为是不能改变的,所以只好用Debug模式观察局部变量而这种模式是为正式调试而设计的。你应该使用调试。
试一试