为什么子 AppDomain 中的 StackOverflowException 会终止父 AppDomain?

发布于 2024-10-18 16:54:04 字数 1550 浏览 7 评论 0原文

我的印象是 AppDomain 是相互隔离的。似乎在 StackOverException 的情况下,情况并非如此。

为了演示这个问题,我创建了一个简单的控制台应用程序,其唯一目的是生成一个新的 AppDomain,我在其中加载一个非常简单的程序集并调用其方法之一。该方法恰好抛出 StackOverflowException。这导致我的控制台应用程序毫不客气地终止。

我期望的行为是“子”AppDomain 在此类异常中崩溃并烧毁,但让在“父”AppDomain 中运行的控制台应用程序毫发无伤。

这可能吗?

更新:这是一些代码。两个异常处理程序都没有被命中。

    class Program
    {
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

            // create app domain
            var domain = AppDomain.CreateDomain("MyDomain");

            // create a component
            var component = (MyComponent)domain.CreateInstanceAndUnwrap(
                "AppDomainMonitor.Component", 
                typeof(MyComponent).FullName);

            // create a thread from a method on this component
            var thread = new Thread(component.CauseStackOverflow);

            // start the thread
            thread.Start();

            Console.ReadKey();
        }

        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            // never hit
        }
    }

    public class MyComponent : MarshalByRefObject
    {
        public void CauseStackOverflow()
        {
            try
            {
                Infinite();
            }
            catch (Exception ex)
            {
                // never hit
            }
        }


        void Infinite()
        {
            Infinite();
        }
    }

I was under the impression that AppDomains are isolated from each other. It seems that in the case of a StackOverException, this isn't the case.

To demonstrate the issue, I created a simple console application whose only purpose is to spawn a new AppDomain, into which I load a very simple assembly and call one of its methods. This method happens to throw a StackOverflowException. This causes my console application to terminate unceremoniously.

My desired behavior is for the "child" AppDomain to crash and burn on such an exception, but leave my console application, running in the "parent" AppDomain, unscathed.

Is this possible?

UPDATE: here is some code. Neither of the exception handlers are hit.

    class Program
    {
        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;

            // create app domain
            var domain = AppDomain.CreateDomain("MyDomain");

            // create a component
            var component = (MyComponent)domain.CreateInstanceAndUnwrap(
                "AppDomainMonitor.Component", 
                typeof(MyComponent).FullName);

            // create a thread from a method on this component
            var thread = new Thread(component.CauseStackOverflow);

            // start the thread
            thread.Start();

            Console.ReadKey();
        }

        static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            // never hit
        }
    }

    public class MyComponent : MarshalByRefObject
    {
        public void CauseStackOverflow()
        {
            try
            {
                Infinite();
            }
            catch (Exception ex)
            {
                // never hit
            }
        }


        void Infinite()
        {
            Infinite();
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

焚却相思 2024-10-25 16:54:04

AppDomain 之间仅隔离托管内存。如果一个线程在任何AppDomain中抛出异常,这将导致整个应用程序崩溃。

我认为最好的解决方案是确保每个线程(或线程池工作项)上的所有异常都得到正确处理。

然而,有一个 hack,其中包括在 App.Config 文件中应用此配置:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <runtime>
    <legacyUnhandledExceptionPolicy enabled="1"/>
  </runtime>
</configuration>

自 .Net 2.0 以来,未处理的异常会导致进程崩溃,但您可以使用此技巧恢复到旧策略。

我会谨慎使用这个方法,因为通常最好是让进程崩溃而不是默默地失败。您可以在 AppDomain.UnhandledException 中添加跟踪,以便在发生未处理的异常时收到通知并进行适当的处​​理。

编辑

您对 StackOveflowException 的看法是正确的,因为 .Net 2.0 此异常无法由用户代码处理。 (请参阅 msdn 中此页面的“备注”部分)。

有一种方法可以通过创建自定义 CLR 主机来覆盖此问题,但这似乎是一件疯狂的事情。我想您将不得不忍受它,或者如果您确实需要这种容错能力,您可以创建子进程而不是 AppDomain。

Only the managed memory is isolated between AppDomains. If a thread throws an exception in any AppDomain, this will cause the whole application to crash.

I think the best solution is to ensure that all exceptions are properly handled on every thread (or thread pool work items).

There is however a hack which consist of applying this configuration in the App.Config file:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <runtime>
    <legacyUnhandledExceptionPolicy enabled="1"/>
  </runtime>
</configuration>

Unhandled exceptions are crashing the process since .Net 2.0, but you can revert to the old policy using this trick.

I would use this cautiously tough as it's often best to let processes crash instead of failing silently. You can add traces in AppDomain.UnhandledException to be notified when unhandled exception occurs and handle them appropriately.

EDIT

You are right about StackOveflowException, since .Net 2.0 this exception cannot be handled by user code. (See the Remarks section of this page in msdn).

There is a way to override this by creating a custom CLR host, but this seems like a crazy thing to do. I guess you'll have to live with it or you can create child process instead of AppDomain if you really need this kind of fault tolerance.

酷到爆炸 2024-10-25 16:54:04

我想问题是您调用的方法导致主 AppDomain 中的异常,即您调用主 AppDomain 中的某个方法,该方法从子 AppDomain 调用问题方法。子 AppDomain 中出现异常,但它会沿着调用堆栈向上传播到您的调用 AppDomain(主 AppDomain)。尝试完全从子 AppDomain 调用此方法。例如,在子 AppDomain 中生成一个线程,以便该线程应该调用问题方法。

I suppose the problem is that you call method causing an exception from within your main AppDomain, that is you call some method in main AppDomain, this method calls problem method from child AppDomain. Exception rises in child AppDomain, but it is propagated up the call stack to your calling AppDomain (main AppDomain). Try to call this method from child AppDomain entirely. For example, spawn a thread in child AppDomain, so that this thread should call problem method.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文