【问题标题】:Debugging whilst paused and 'cannot evaluate expression'在暂停和“无法评估表达式”时进行调试
【发布时间】:2010-09-02 11:54:08
【问题描述】:

使用 Visual Studio,在附加到进程并按下暂停(Break-All)后,切换到所需线程并使用“快速监视”窗口检查一些数据,比如

MySingletonClass.Instance.Data

有时我会得到这个:

无法计算表达式,因为当前线程处于睡眠、等待或加入状态

或者这个(当试图查看数据的某些属性时):

无法计算表达式,因为本机框架位于调用堆栈的顶部。

坦率地说,我不在乎,我只是想看看数据!我知道有多种方法可以解决这个问题,即:

  1. 在线程上设置断点并等待它被命中(麻烦,并不总是可行)
  2. 转储进程并重新加载到 VS(即使这样我仍然遇到第二个错误)
  3. windbg

假设你可以看到这些数据,如果你大概使用了 windbg,为什么我们都不能利用更简单、更漂亮的 VS 在附加到进程时检查对象?

【问题讨论】:

    标签: .net visual-studio debugging


    【解决方案1】:

    为什么我们不能这样做?我们不能这样做,因为 Visual Studio 监视窗口不只是从内存中检索数据并显示它。它实际上执行托管代码(这就是“评估表达式”的意思)。特别是,它几乎总是执行ToString() 方法来显示用户可读的结果。

    关键在于它在您正在调试的进程/线程中执行此代码。这可确保表达式的计算方式与它实际上在您正在调试的代码中的方式相同。这样做的缺点是它只能在托管指令之间执行,但不能在本机代码处于活动状态时执行,也不能在阻塞线程中执行。

    我们能做些什么?如果您实际上是在调试托管应用程序,并且您在本机堆栈帧中,只需重复按 F10 或 Shift+F11 直到您返回托管代码。然后你可以评估表达式。但是,对于完全本机进程和处于阻塞状态的线程,我不知道有任何解决方法。

    【讨论】:

      【解决方案2】:

      这里有一个link 来讨论这个问题。显然,当函数参数是结构时,堆栈上调用函数所需的总内存超过了一些神奇的数字 Visual Studio 调试器呕吐。

      来自 OpenTK 框架讨论的其他 link

      【讨论】:

        【解决方案3】:

        只需按 Shift-F11 直到托管堆栈帧位于堆栈顶部,您就可以在 VS 中执行您想要的操作。

        这基本上归结为这样一个事实,即在流程执行期间的某些点评估表达式是不安全的,否则您可能会破坏运行时。 WinDbg 不会保护您的运行时。 VS 可以。

        【讨论】:

        • 在我看到的大多数情况下是由于长时间运行的方法,例如 SQL 查询。
        【解决方案4】:

        问题是,那不是你想看的数据,它是运行一些代码的结果。在 .Net 中属性实际上只是变相的方法,所以为了获取属性的值,Visual Studio 需要执行应用程序代码(这个特性称为 FuncEval)。

        此代码必须在某个线程上运行,而 VS 的作用是为此使用其中一个应用程序线程。有a number of situations VS 无法运行代码以产生结果,那就是当您看到您正在谈论的错误消息时。

        【讨论】:

        • 谢谢,这解决了一些问题,但是当我获取转储文件时,我能够以某种方式看到数据,例如加载转储文件,切换到“睡眠”线程,然后快速查看在“this”上,数据就会显示出来。
        • “显示”我的意思是我没有得到“无法评估表达式,因为当前线程处于睡眠、等待或加入状态”
        【解决方案5】:

        如果您单步执行下一条指令,调试器可能有足够的时间在超时之前对其进行评估。

        注意,这并不总是有效。

        【讨论】:

          【解决方案6】:

          如果您的项目是客户端服务器,请尝试重新上传引用 MySql.Data.dll

          【讨论】:

            【解决方案7】:

            我知道这是一个杂牌,但我对它的工作方式很满意。在我的 Main() 方法结束时,它最初启动所有内容并创建所有其他数据结构和线程,然后终止,我坚持:

                    while (true)
                    {
                        // This infinite while loop just gives me a convenient place for a 
                        // breakpoint, so I can see everything everywhere during debugging.
                        Thread.Sleep(100);
                    }
            

            我没有做“全部中断”,而是在花括号 { 上放置一个断点。程序中断。我有一个可用的线程,以及对所有内容的引用,因此我可以轻松浏览所有数据结构和所有线程,随时随地查看所有内容。

            【讨论】:

              猜你喜欢
              • 2014-02-05
              • 2011-06-17
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多