2011-09-20 70 views
5

如果我这样写:为什么.NET不为StackOverflow异常记录堆栈跟踪?

class Program 
{ 
    static void Main(string[] args) 
    { 
     throw new Exception("lol"); 
    } 
} 

,并运行在命令行的EXE,我得到了我的事件日志中的两个项目。一个是应用程序错误,表示存在未处理的异常,另一个包含堆栈跟踪,源为.NET运行时。

如果我这样写:

class Program 
{ 
    static void Main(string[] args) 
    { 
     Recurse4Evr(); 
    } 

    static void Recurse4Evr() 
    { 
     Recurse4Evr(); 
    } 
} 

我只得到我的事件日志,它说应用程序错误的一个条目,并且有一个堆栈溢出异常。堆栈跟踪没有第二个条目,所以它基本上没用。

为什么不记录堆栈跟踪?如果我设置DebugDiag并将其附加到我的进程,然后出现堆栈溢出,DebugDiag可以记录堆栈跟踪。很显然,堆栈跟踪以某种方式可用于外部世界。如果运行时正在终止进程,因为它检测到了堆栈溢出,那么它也知道堆栈是什么。

在有许多复杂交互的大型应用程序中,通常不可能重新创建导致堆栈溢出的条件。在这种情况下,堆栈跟踪是了解发生情况的唯一方法。为什么微软决定记录这些信息并不重要?有没有一个合理的设计决定不明显?

+4

我的猜测是生成堆栈跟踪进程需要函数调用,因为堆栈溢出而无法工作。调试器通过能够使用自己的数据结构和(有希望)健康的堆栈来遍历堆栈。 – siride

+0

这是一个很好的问题!我不知道它是否与检测堆栈溢出的方式有关......在.Net 2.0之后,似乎你也无法捕获它,所以它看起来好像是按照一组特殊的规则来玩。 –

+0

[C#捕获堆栈溢出异常]的可能重复(http://stackoverflow.com/questions/1599219/c-catch-a-stack-overflow-exception) – balexandre

回答

0

这显然是不可能的。如果你想要一个堆栈跟踪,以便找到杀死你的应用程序的有害代码,你需要附加一个第三方工具,如DebugDiag或AdsPlus。祝你好运,基本上没有这些工具的文档。

1

堆栈溢出被认为是不可恢复的情况,因此运行时会终止进程。

总结:

from Damien_The_Unbeliever

从MSDN页面上StackOverflowException S:

在.NET Framework的早期版本中,您的应用程序可以赶上一个StackOverflowException对象(例如,从无限递归中恢复)。然而,这种做法目前令人沮丧,因为需要大量额外的代码才能可靠地捕获堆栈溢出异常并继续执行程序。

从.NET Framework 2.0版开始,StackOverflowException对象不能被try-catch块捕获,并且相应的进程默认终止。因此,建议用户编写代码来检测和防止堆栈溢出。例如,如果您的应用程序依赖于递归,请使用计数器或状态条件来终止递归循环。请注意,承载公共语言运行库(CLR)的应用程序可以指定CLR卸载发生堆栈溢出异常的应用程序域,并让相应的进程继续。有关更多信息,请参阅ICLRPolicyManager接口并承载公共语言运行时。


from JaredPar

与2.0开始出现StackOverflow异常只能在下列情况下被捕获。

  1. CLR是在宿主环境中,其中主机特别允许的StackOverflow例外处理
  2. 该计算器异常是由用户代码抛出,而不是由于实际的堆栈溢出情况中运行(Reference
+0

我不想抓到它。我问为什么当你的程序终止时,以及运行时日志记录事件日志中有错误,为什么它不包括堆栈跟踪。 – dan

+0

也,我认为微软的“建议”是非常简单的。当然,这对递归算法是有意义的 - 当然你应该以迭代的方式写斐波纳契。我的情况不是递归算法,在异常事件处理程序中的记录器中有错误。记录器投掷,然后再次触发事件处理程序,它再次抛出等。我只能使用DebugDiag找到导致溢出的原因。微软的建议基本上是“不要编写有bug的代码”。 – dan