首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >调试挂起与DebugDiag -神秘异常

调试挂起与DebugDiag -神秘异常
EN

Stack Overflow用户
提问于 2020-06-19 16:04:30
回答 1查看 376关注 0票数 1

最近,我正在调试我们的应用程序中的“挂起”问题。我对这个工具很陌生,但是对于我在DebugDiag分析中看到了什么有一个特别的问题。我会另行发帖回答其他问题。它有一个题为“以前的.NET异常(所有.NET堆中的异常)”的部分,其中列出了5个异常:

代码语言:javascript
复制
Exception Type                          Count    Message     Stack Trace
System.Exception                        1        <none>      ;
System.OutOfMemoryException             1        <none>      ;
System.StackOverflowException           1        <none>      ;
System.ExecutionEngineException         1        <none>      ;
System.Threading.ThreadAbortException   2        <none>      ; 

有人能帮我理解几件事吗?

  • 这一节的标题是什么意思?“以前的.NET例外”?
  • 如果有异常抛出,为什么它不会出现在日志中,为什么应用程序不会中止而不是挂起呢?我已经检查了我们的代码是否有任何可能的异常被“吃掉”。
  • 为什么没有消息或堆栈跟踪相关联?我获得了.dmp文件中其他所有内容的调试信息,包括所有线程的。是否有更好的方法/工具来确定这些来源?

提前感谢!

EN

回答 1

Stack Overflow用户

发布于 2020-06-26 11:41:02

这一节的标题是什么意思?“以前的.NET例外”?

当发生异常时,它可能由使用try{} catch{}构造的代码处理。在许多情况下(至少我在代码中看到的情况),异常正在转换为其他异常。原因通常是某种API,它只会抛出“属于”的异常,即库定义的类型的异常:

代码语言:javascript
复制
try 
{
    DoSomething();
}
catch (ArgumentException)
{
    throw new MyWhateverLibraryException();
}

而且,人们通常不设置InnerException属性,尽管这样做并不难:

代码语言:javascript
复制
try 
{
    DoSomething();
}
catch (ArgumentException argex)
{
    var myex = new MyWhateverLibraryException();
    myex.InnerException = argex;
    throw myex;
}

无论如何,如果不正确执行,原始异常就会消失,并且调试这种情况会变得更加困难。

然而,一个异常将不会花很长时间来泡沫向上,并导致崩溃导致崩溃转储。在许多情况下,垃圾收集器将没有足够的时间收集不再引用的异常。

DebugDiag试图使丢失的异常对您可用。它所做的基本上是列出所有在其名称中有异常的对象,假设它们是异常。这相当于SOS命令!dumpheap -type Exception

在某些情况下,您可能会发现有兴趣的例外,所以这可能是有帮助的。但在很多情况下,它只会列出6种默认的异常,这是更令人困惑而不是有帮助的。

如果有异常抛出,为什么它不会出现在日志中,为什么应用程序不会中止而不是挂起呢?

您看到的6个异常是“默认”异常,它存在于每个.NET项目中,甚至在一个简单的Hello项目中也是如此。这些异常在每个AppDomain中只创建一次,并且始终具有默认的AppDomain。

它们是为特殊的场合而创造的。其中一些问题可以很容易地解释:

  • OutOfMemoryException:当内存已满时,可能不可能对一个对象执行new。创建OutOfMemoryException将再次导致OutOfMemoryException。
  • StackOverflowException:如果堆栈已满,则不能调用其他方法。对于.NET,可能需要调用一个方法来调用构造函数。这样做将再次导致StackOverflowException。
  • ExecutionEngineException:如果.NET运行时已损坏,则可能无法再创建该异常。(此异常在.NET核心中已过时,因此在.NET核心项目中可能不存在)

ThreadAbortExceptions可能也有类似的原因。我真不知道普通的例外有什么好处。

为什么没有消息或堆栈跟踪相关联?

那是因为他们还没被扔出去。其中一些在抛出时甚至可能得不到调用堆栈,例如,在发生OutOfMemoryException的情况下,没有用于构建堆栈跟踪的内存。StackOverflowException也是如此。

是否有更好的方法/工具来确定这些来源?

不是的。这只是知识的问题。现在你获得了这样的知识:-)

这笔赏金与

从有信誉的来源寻找答案

我不知道什么才算是有信誉的来源。我可以提供一个存档的苔丝·费兰德斯的博客文章。苔丝·费兰德斯是微软ASP.NET升级工程师。你会发现,在2009年,违约的例外并不像现在那么多。

如果你想要一本书,那么它很可能在Mario的“高级.NET调试”书中。我有这本书,但目前没有,否则我会查一下的。

.NET CLR源代码中可以找到appdomain.cpp,它有一个名为void SystemDomain::CreatePreallocatedExceptions()的方法。甚至我都不知道有一个正常的ThreadAbortException和一个“粗鲁”的ThreadAbortException。哇!

代码语言:javascript
复制
EXCEPTIONREF pRudeAbortException = (EXCEPTIONREF)AllocateObject(g_pThreadAbortExceptionClass);
...
EXCEPTIONREF pAbortException = (EXCEPTIONREF)AllocateObject(g_pThreadAbortExceptionClass);

用于自己测试某些语句的源代码:

代码语言:javascript
复制
using System;

namespace DefaultExceptions
{
    class ThisDoesNotDeriveFromException
    { }
    class Program
    {
        static void Main()
        {

            var noexception = new ThisDoesNotDeriveFromException();
            Console.WriteLine("This is just an example to demonstrate the presence of some default exceptions.");
            Console.WriteLine("Create a crash dump now, so you can analyze it with WinDbg and SOS or DebugDiag.");
            Console.WriteLine("Commands:");
            Console.WriteLine(".loadby sos clr");
            Console.WriteLine("!dumpheap -type Exception");
            Console.ReadLine();
            Console.WriteLine(noexception.ToString()); // avoid noexception being GC'd
        }
    }
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62474245

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档