为什么ExecuteCodeWithGuaranteedCleanup不起作用?

时间:2009-04-14 17:21:46

标签: c#

我试图“测量”堆栈深度。以下程序为什么不打印任何内容?

class Program
{
    private static int Depth = 0;

    static void A(object o) 
    {
        Depth++;
        A(o);
    }

    static void B(object o, bool e)
    {
        Console.WriteLine(Depth);
    }

    static void Main(string[] args)
    {
        RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(A, B, null);
    }
}

有些答案只包含来自MSDN的引用,例如“从.NET Framework 2.0版开始,无法通过try-catch块捕获StackOverflowException对象,并且默认情况下会终止相应的进程。”相信我,有时(当有足够的堆栈空间时)它可以是cought,下面打印一些数字就好了:

class Program
{
    private static int depth = 0;

    static void A(object o)
    {
        depth++;
        if (Environment.StackTrace.Length > 8000)
            throw new StackOverflowException("Catch me if you can.");
        A(o);
    }

    static void B(object o, bool e)
    {
        Console.WriteLine(depth);
    }

    static void Main(string[] args)
    {
        RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(A, B, null);
    }
}

4 个答案:

答案 0 :(得分:6)

关于你的编辑,我不认为抛出StackOverflowException的用户代码与抛出它的CLR相同。

有一些关于它的讨论here

  杰弗里(Richter,Applied Microsoft® .NET Framework Programming的作者)评论适用于实际堆栈溢出,即堆栈溢出   如果您的代码包含无限递归,则会发生这种情况,例如:

     

void MyMethod(){MyMethod(); }

     

如果你扔了   StackOverflowException自己,它   将像其他任何一样处理   例外,杰弗里的评论确实如此   不适用。

     

此外,杰弗里的评论说:“如果   在CLR内发生堆栈溢出   自己...“。所以,如果.NET VM可以   检测堆栈溢出“干净”,   即没有将ITSELF运行到   堆栈溢出,然后你应该得到一个   StackOverflowException和你的捕获   最后块应该执行为   通常。但是,在悲惨的情况下   VM ITSELF进入堆栈   溢出,你不会那么幸运:   VM不会传播   StackOverflowException(但崩溃了   一些其他奇怪的方式)和你的捕获   最后块不会执行。

     

士气是:小心无限   递归,因为你没有   100%保证VM将检测到   并清楚地发出信号!

     

布鲁诺。

澄清了自从OP引用该书以来“杰弗里”是谁。

答案 1 :(得分:5)

如果你想捕获它,将它加载到另一个进程(通过远程处理回调你的进程)并让恶意代码在那里执行。另一个过程可能会终止,你可以得到一个整洁的SOE弹出管道末端 - 没有相当不方便的例外的不利影响。

请注意,同一进程中的单独AppDomain不会删除它。

如果您想从异常中获取堆栈跟踪,以下代码将为您提供良好的正义:

    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Recurse(0);
            }
            catch (Exception ex)
            {
                StackTrace st = new StackTrace(ex);
                // Go wild.
                Console.WriteLine(st.FrameCount);
            }
            Console.ReadLine();
        }

        static void Recurse(int counter)
        {
            if (counter >= 100)
                throw new Exception();
            Recurse(++counter);
        }
    }

答案 2 :(得分:3)

根据MSDN

  

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

     

从.NET Framework开始   版本2.0,StackOverflowException   try-catch无法捕获对象   块和相应的过程是   默认终止。所以,   建议用户编写代码   检测和防止堆栈   溢出。例如,如果你的   应用程序取决于递归,使用   反击或国家条件   终止递归循环。注意   托管的应用程序   公共语言运行库(CLR)可以   指定CLR卸载   应用程序域所在的堆栈   溢出异常发生并让   相应的过程继续。对于   更多信息,请参阅   ICLRPolicyManager接口和   托管公共语言运行时。

由于这个事实,我不相信你能做你想做的事,因为`StackOverflowException将终止进程。

答案 3 :(得分:0)

从.NET Framework 2.0版开始,try-catch块无法捕获StackOverflowException对象,默认情况下会终止相应的进程

相关问题