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