C#捕获堆栈溢出异常

C# catch a stack overflow exception

我得到了对方法的递归调用,该方法引发了堆栈溢出异常。第一个调用被try catch块包围,但未捕获异常。

堆栈溢出异常的行为是否特殊?我能正确地捕捉/处理异常吗?

注:如果相关:

  • 未在主线程中引发异常

  • 代码引发异常的对象由assembly.loadFrom(…).createInstance(…)手动加载。


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

  • clr正在托管环境*中运行,主机专门允许处理stackoverflow异常。
  • stack overflow异常由用户代码引发,而不是由于实际的堆栈溢出情况(参考)
  • >"hosted environment"如"my code hosts clr and i configure clr's options"and not"my code runs on shared hosting"


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

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

    1
    2
    3
    using System.Threading;
    Thread T = new Thread(threadDelegate, stackSizeInBytes);
    T.Start();

    您可以使用System.Diagnostics.StackTrace frameCount属性计算已使用的帧数,并在达到帧限制时引发自己的异常。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    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();
        }
    }

    快去拿奶酪。;)


    从StackOverflowExceptions上的msdn页面:

    In prior versions of the .NET
    Framework, your application could
    catch a StackOverflowException object
    (for example, to recover from
    unbounded recursion). However, that
    practice is currently discouraged
    because significant additional code is
    required to reliably catch a stack
    overflow exception and continue
    program execution.

    Starting with the .NET Framework
    version 2.0, a StackOverflowException
    object cannot be caught by a try-catch
    block and the corresponding process is
    terminated by default. Consequently,
    users are advised to write their code
    to detect and prevent a stack
    overflow. For example, if your
    application depends on recursion, use
    a counter or a state condition to
    terminate the recursive loop. Note
    that an application that hosts the
    common language runtime (CLR) can
    specify that the CLR unload the
    application domain where the stack
    overflow exception occurs and let the
    corresponding process continue. For
    more information, see
    ICLRPolicyManager Interface and
    Hosting the Common Language Runtime.


    正如一些用户所说,您无法捕获异常。但是,如果您正在努力找出它发生的位置,您可能希望配置Visual Studio在抛出时中断。

    为此,您需要从"调试"菜单中打开异常设置。在旧版本的Visual Studio中,它位于"调试"-"异常";在新版本中,它位于"调试"-"Windows"-"异常设置"。

    打开设置后,展开"公共语言运行时异常",展开"系统",向下滚动并选中"System.StackOverflowException"。然后,您可以查看调用堆栈并查找调用的重复模式。这应该让您了解在哪里修复导致堆栈溢出的代码。


    如前几次所述,不可能捕获由于进程状态损坏而由系统引发的StackOverflowException。但是有一种方法可以将例外作为一个事件来注意:

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

    Starting with the .NET Framework version 4, this event is not raised for exceptions that corrupt the state of the process, such as stack overflows or access violations, unless the event handler is security-critical and has the HandleProcessCorruptedStateExceptionsAttribute attribute.

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

    In the .NET Framework versions 1.0 and 1.1, an unhandled exception that occurs in a thread other than the main application thread is caught by the runtime and therefore does not cause the application to terminate. Thus, it is possible for the UnhandledException event to be raised without the application terminating. Starting with the .NET Framework version 2.0, this backstop for unhandled exceptions in child threads was removed, because the cumulative effect of such silent failures included performance degradation, corrupted data, and lockups, all of which were difficult to debug. For more information, including a list of cases in which the runtime does not terminate, see Exceptions in Managed Threads.


    是的,从clr 2.0堆栈溢出被认为是不可恢复的情况。所以运行时仍然关闭进程。

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


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

    在许多网站上,你会发现人们说,避免这种情况的方法是使用不同的AppDomain,因此如果发生这种情况,域将被卸载。这是绝对错误的(除非您托管了自己的clr),因为clr的默认行为将引发killprocess事件,从而导致默认的appdomain。


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


    这是不可能的,而且有一个很好的理由(例如,考虑一下周围的所有捕获物(例外))。

    如果要在堆栈溢出后继续执行,请在其他AppDomain中运行危险代码。可以将CLR策略设置为在溢出时终止当前AppDomain,而不影响原始域。