【问题标题】:Why I cannot see local variables in the middle of the stack while debugging ASP.NET Core source code from Visual Studio为什么在从 Visual Studio 调试 ASP.NET Core 源代码时看不到堆栈中间的局部变量
【发布时间】:2020-09-26 21:53:03
【问题描述】:

我正在尝试通过调试基于 API 项目模板的“开箱即用”WeatherForecast 应用程序来探索 ASP.NET Core 管道。

根据各种资源,我在 VS 中设置了以下配置:

  1. 工具->选项->调试->常规

    • 启用 .NET Framework 源单步执行 - 已选中
    • 启用源链接支持 - 选中
    • 在模块加载时抑制 JIT 优化 - 已检查
    • 使用托管兼容模式(尝试了选中/未选中的两种组合,但它似乎确实会影响任何东西)
  2. 工具->选项->调试->符号

    • 加载所有模块,除非排除 - 已选择
    • 作为符号的位置,我尝试了 Microsoft 符号服务器和集成到 JetBrains dotPeek 中的符号服务器
  3. 项目属性->调试->环境变量

    • COMPLUS_JITMinOpts = 1 [根据 https://github.com/dotnet/runtime/issues/5767]。事实上,我相信这就是“抑制模块加载时的 JIT 优化”的作用。
    • COMPLUS_ZapDisable = 1 [避免加载原生图像]
  4. 项目属性->构建

    • 优化代码 - 未选中

当我启动调试器并转到 Debug->Windows->Modules 时,我可以看到所有 ASP.NET Core dll 都加载了符号,并且 Optimized 列设置为“No”。 但是,当我在控制器中遇到断点并遍历调用堆栈时,Locals 窗口中会出现很多错误:

'无法获取局部变量或参数的值,因为它在该指令指针处不可用,可能是因为它已被优化掉'

我认为优化没有关闭,但我可以在 asp.net 源代码中的函数内部打断点并观察局部变量。 当执行指针移动到不同的函数时,问题就出现了。一旦发生这种情况,这些局部变量就会变得不可用。

在这个线程https://github.com/aspnet/Mvc/issues/8375 中,有人建议构建程序集的调试版本,但是我无法完全理解为什么它是必要的。 我的理解是编译器只是通过删除 NOP 指令和死代码块使 IL 代码更干净。真正的优化工作由 JIT 完成,可以通过 COMPLUS_JITMinOpts 和 COMPLUS_ZapDisable 标志控制。

有没有办法在遍历堆栈时避免这些“可能是因为它已被优化掉”消息?似乎我在这里遗漏了一些重要的概念,但我不知道从哪里看。

我在 VS2019(核心 3.1)和 VS2017(核心 2.2)中都有相同的行为

【问题讨论】:

  • 嗨,sergei,关于这个问题的任何更新?如果我的回答能帮助你处理和理解这个问题,请不要忘记accept it。如果没有,请随时告诉我们:)
  • 嗨,佩里!提供的信息使我走上了正确的轨道。谢谢!最终,我从源代码构建了 asp.net 核心,并安装了基于 guideline 的最新调试二进制文件。一旦我添加了 Nuget.config(指向本地调试二进制文件)并将 Project Properties->Debug->Launch 设置为“Project”,我就能够看到堆栈中的变量。我接受了答案。
  • 在我的例子中,变量实际上是有值的,直到它们进入抛出条件。由于某种原因,当该特定行被触发抛出异常时,所有局部变量都被优化掉了。我最终使用断点操作来写入一些数据以帮助追踪我的问题。我注意到的另一个令人讨厌的方面是,任何TypeTypeInfo 成员似乎仍然得到了优化。这似乎是一个早就应该解决的问题,但唉。

标签: .net asp.net-core .net-core visual-studio-debugging


【解决方案1】:

试试这些:

1) 不确定您使用了哪些其他设置。为了给您更好的指导,我建议您可以先尝试在工具-->导入和导出设置-->全部重置下重置所有vs设置设置,以便避免其他疏忽的选项。

2)如果您使用Release模式,请进入Project Properties-->Build--> 高级-->将调试信息更改为Full。使用与 Debug 相同的模式。

3)请取消选中项目Properties-->Build下的Optimize Code复选框。

然后,勾选Tools-->Debugging下的Suppress JIT optimization on module load(Managed only) -->常规

4) 删除binobj 文件夹,然后重新构建您的项目。

5)你可以试试convince the JIT compiler not to optimize the code is to use an INI file with the name of the assembly in the same folder the assembly is in with the contents

更新 1

我的解决方案会让Release模式更接近Debug模式,由于它仍然看不到局部变量,恐怕Release模式不能随心所欲地改变。

让我更详细地解释一下:

具体发布模式不是为了调试目的而产生的,它是最终产品的最佳发布,显然如果发生各种意外情况,可能会发生你想在你的代码中查看堆栈和变量,这是一个真实的东西,所以我们不建议这样做。

Debug模式下,pdb文件很大,里面包含了你想要的所有调试类型,只有在调试模式下,你才能享受到所有的调试类型。调试模式用于调试项目,Release是在调试项目没有问题的情况下创建最终优化版本,以减少发布,方便发布者分发程序.

因此,在Release模式下调试时,无法避免问题。

我的解决办法是让Release更接近于Debug模式,看来Release的root行为是无法改变的,所以你必须使用Debug模式来观察局部变量和它设计的这个模式正式调试。您应该使用调试。

试一试

【讨论】:

  • 我按照 VS2019(v16.7.4) 中的步骤操作,但不幸的是,同样的行为仍然存在。在调试配置中构建 asp.net 程序集是一种解决方案吗?
  • 其实debug模式是真正的debug模式,而release模式是发布项目的,确实有完整的debug能力。并且由于我的解决方法不起作用,因此,我认为通过我的解决方案无限接近调试模式的发布模式仍然具有发布的行为。这是根本原因,无法改变。所以当你使用debug模式查看局部变量是唯一的解决办法,你可以试一试。
  • 我已经更新了我的答案,你可以检查一下。希望对您有所帮助!
  • 启用 Suppress JIT optimization 并删除对我有用的 binobj 文件夹。
猜你喜欢
  • 1970-01-01
  • 2021-06-25
  • 1970-01-01
  • 2015-07-15
  • 2012-07-12
  • 1970-01-01
  • 1970-01-01
  • 2017-07-29
  • 1970-01-01
相关资源
最近更新 更多