在 .NET 中遇到一些 StackOverflowExceptions 后,我注意到它们完全绕过了 .NET 提供的未处理异常处理程序(Application.ThreadException / AppDomain.UnhandledException)。这非常令人不安,因为我们在这些异常处理程序中有关键的清理代码。
有什么办法可以克服这个吗?
存在三种所谓的“异步异常”。那是 ThreadAbortException、OutOfMemoryException 和提到的 StackOverflowException。这些异常允许发生在代码中的任何指令中。
而且,还有一种方法可以克服它们:
最简单的是 ThreadAbortException。当前代码在 finally 块中执行时。ThreadAbortExceptions 有点“移动”到 finally 块的末尾。因此,finally 块中的所有内容都不能被 ThreadAbortException 中止。
要避免 OutOfMemoryException,您只有一种可能性:不要在堆上分配任何东西。这意味着您不能创建任何新的引用类型。
要克服 StackOverflowException,您需要框架的一些帮助。这种帮助体现在受约束的执行区域中。在执行实际代码之前分配所需的堆栈,另外还确保代码已经 JIT 编译,因此可以执行。
在受约束的执行区域中执行代码有三种形式(复制自BCL 团队博客):
您可以在这些博客文章中找到更多信息:
BCL 团队博客中的受限执行区域和其他勘误表 [Brian Grunkemeyer]。
Joe Duffy 的关于原子性和异步异常失败的博客,其中他很好地概述了 .net 框架中的异步异常和健壮性。
并不真地; 堆栈溢出或 CLR 本身发生内存不足异常意味着出现严重错误(当我一直是个笨蛋并创建递归属性时,我通常会得到它)。
当此状态发生时,CLR 无法分配新的函数调用或内存以使其能够调用异常处理程序;这是一个“我们现在必须停止”的场景。
但是,如果您自己抛出异常,您的异常处理程序将被调用。
堆栈溢出不是您可以从中恢复的东西,因为它甚至无法分配更多堆栈内存来调用您的异常处理程序。
你唯一能做的就是找出原因并防止它发生(例如,小心递归,不要在堆栈上分配大对象)。
吹镖把它钉在上面。Dumbass 递归属性,他喜欢这样称呼它。真的只是输入代码太快的问题。
private Thing _myThing = null;
Public Thing MyThing
{
get{
return this.MyThing;}
set{
this.MyThing = value;}
}