C#捕获堆栈溢出异常

Tot*_*oto 110 c# stack-overflow try-catch

我得到一个递归调用一个抛出堆栈溢出异常的方法.第一个调用被try catch块包围,但没有捕获异常.

堆栈溢出异常是否以特殊方式运行?我可以正确捕获/处理异常吗?

注意:如果相关:

  • 主线程中没有抛出异常

  • 代码抛出异常的对象由Assembly.LoadFrom(...)手动加载.CreateInstance(...)

Jar*_*Par 104

从2.0开始,只能在以下情况下捕获StackOverflow异常.

  1. CLR正在托管环境*中运行,其中主机特别允许处理StackOverflow异常
  2. 用户代码抛出stackoverflow异常,而不是由于实际的堆栈溢出情况(参考)

* "托管环境",如"我的代码主机CLR和我配置CLR的选项"而不是"我的代码在共享主机上运行"

  • 如果无法捕获任何相关的scebario,为什么StackoverflowException对象存在? (27认同)
  • 如何在托管环境中处理StackOverflowExceptions?我问的原因是因为我运行托管环境,而且我遇到了这个问题,它会破坏整个应用程序池.我宁愿让它中止线程,它可以放松回到顶部,然后我可以记录错误并继续,而不会杀死所有apppool的线程. (10认同)
  • @Manu至少有几个原因.1)它是否可以在1.1中被捕获,因此有目的.2)如果您正在托管CLR,它仍然可以被捕获,因此它仍然是一个有效的异常类型 (9认同)
  • 如果无法捕获...为什么不解释发生了什么的Windows事件默认包括完整堆栈跟踪? (3认同)

小智 46

正确的方法是修复溢出,但....

你可以给自己一个更大的堆栈: -

using System.Threading;
Thread T = new Thread(threadDelegate, stackSizeInBytes);
T.Start();
Run Code Online (Sandbox Code Playgroud)

您可以使用System.Diagnostics.StackTrace FrameCount属性来计算您使用的帧,并在达到帧限制时抛出您自己的异常.

或者,您可以计算剩余堆栈的大小,并在低于阈值时抛出您自己的异常: -

class Program
{
    static int n;
    static int topOfStack;
    const int stackSize = 1000000; // Default?

    // The func is 76 bytes, but we need space to unwind the exception.
    const int spaceRequired = 18*1024; 

    unsafe static void Main(string[] args)
    {
        int var;
        topOfStack = (int)&var;

        n=0;
        recurse();
    }

    unsafe static void recurse()
    {
        int remaining;
        remaining = stackSize - (topOfStack - (int)&remaining);
        if (remaining < spaceRequired)
            throw new Exception("Cheese");
        n++;
        recurse();
    }
}
Run Code Online (Sandbox Code Playgroud)

抓住奶酪吧.;)

  • "奶酪"远不具体.我会去'扔新的CheeseException("Gouda");` (44认同)
  • @ C.Evenhuis虽然毫无疑问Gouda是一种特殊的奶酪,但它应该是RollingCheeseException("Double Gloucester")真的看到http://www.cheese-rolling.co.uk/ (13认同)
  • 大声笑,1)修复是不可能的,因为没有捕捉它你经常不知道它发生在哪里2)增加Stacksize是无用的**无尽的**递归和m 3)在正确的位置检查堆栈就像第一次 (3认同)
  • 但我对乳糖不耐 (2认同)

Dam*_*ver 38

StackOverflowException上的MSDN页面:

在.NET Framework的早期版本中,您的应用程序可以捕获StackOverflowException对象(例如,从无限递归中恢复).但是,目前不鼓励这种做法,因为需要大量额外的代码来可靠地捕获堆栈溢出异常并继续执行程序.

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


Sim*_*mon 21

正如几位用户已经说过的那样,你无法捕获异常.但是,如果您正在努力找出它发生的位置,您可能希望配置visual studio以便在它被抛出时中断.

为此,您需要从"调试"菜单中打开"异常设置".在旧版本的Visual Studio中,这是'Debug' - 'Exceptions'; 在较新的版本中,它位于'Debug' - 'Windows' - 'Exception Settings'.

打开设置后,展开"Common Language Runtime Exceptions",展开"System",向下滚动并选中"System.StackOverflowException".然后你可以查看调用堆栈并查找重复的调用模式.这应该让你知道在哪里寻找修复导致堆栈溢出的代码.

  • 调试 - Windows - 异常设置 (2认同)

Foo*_*tle 15

如上所述,由于进程状态损坏,无法捕获由系统引发的StackOverflowException.但有一种方法可以将异常视为事件:

http://msdn.microsoft.com/en-us/library/system.appdomain.unhandledexception.aspx

从.NET Framework版本4开始,不会针对损坏进程状态的异常(例如堆栈溢出或访问冲突)引发此事件,除非事件处理程序是安全关键的并且具有HandleProcessCorruptedStateExceptionsAttribute属性.

然而,你的应用程序将在退出事件函数后终止(一个非常肮脏的解决方法,是在这个事件中重新启动应用程序哈哈,没有这样做,也永远不会这样做).但它对于伐木来说已经足够了!

在.NET Framework 1.0和1.1版中,运行时捕获在主应用程序线程以外的线程中发生的未处理异常,因此不会导致应用程序终止.因此,可以在不终止应用程序的情况下引发UnhandledException事件.从.NET Framework 2.0版开始,删除了子线程中未处理异常的这一支持,因为此类静默故障的累积影响包括性能下降,数据损坏和锁定,所有这些都难以调试.有关更多信息,包括运行时未终止的案例列表,请参阅托管线程中的例外.


Bri*_*sen 6

是的CLR 2.0堆栈溢出被认为是不可恢复的情况.所以运行时仍然关闭了进程.

有关详细信息,请参阅文档http://msdn.microsoft.com/en-us/library/system.stackoverflowexception.aspx


Mat*_*ley 5

你不能.CLR不会让你.堆栈溢出是致命错误,无法从中恢复.


No *_*ema 5

您不能像大多数帖子那样解释,让我添加另一个区域:

在许多网站上,您会发现人们说避免这种情况的方法是使用不同的AppDomain,因此如果发生这种情况,域名将被卸载.这是绝对错误的(除非您托管您的CLR)因为CLR的默认行为将引发KillProcess事件,从而关闭您的默认AppDomain.