Почему StackOverflowException в дочернем AppDomain завершает родительский AppDomain? - PullRequest
10 голосов
/ 22 февраля 2011

У меня сложилось впечатление, что домены приложений изолированы друг от друга.Кажется, что в случае StackOverException это не так.

Чтобы продемонстрировать проблему, я создал простое консольное приложение, единственная цель которого - создать новый домен приложений, в который я загружаю оченьПростая сборка и вызов одного из ее методов.Этот метод вызывает исключение StackOverflowException.Это приводит к тому, что мое консольное приложение завершается бесцеремонно.

Мое желаемое поведение - чтобы «дочерний» домен приложения зависал и записывался при таком исключении, но оставлял мое консольное приложение, работающее в «родительском» домене приложения, невредимым.

Возможно ли это?

ОБНОВЛЕНИЕ: вот код.Ни один из обработчиков исключений не срабатывает.

    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();
        }
    }

Ответы [ 2 ]

8 голосов
/ 22 февраля 2011

Только управляемая память изолирована между доменами приложений.Если поток генерирует исключение в каком-либо из доменов приложений, это приведет к сбою всего приложения.

Я думаю, что лучшим решением является обеспечение правильной обработки всех исключений в каждом потоке (или рабочих элементах пула потоков).

Однако существует хак, который заключается в применении этой конфигурации в файле App.Config:

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

Необработанные исключения приводят к сбою процесса начиная с .Net 2.0, но вы можете вернуться кстарая политика, использующая этот трюк.

Я бы использовал это осторожно, поскольку часто лучше позволить процессам аварийно завершать работу, чем молча.Вы можете добавить трассировки в AppDomain.UnhandledException, чтобы получать уведомления при возникновении необработанного исключения и обрабатывать их соответствующим образом.

EDIT

Вы правы в отношении StackOveflowException, поскольку .Net 2.0 этоисключение не может быть обработано кодом пользователя.(См. Раздел «Примечания» этой страницы в msdn ).

Существует способ переопределить это, создав собственный хост CLR, но это кажется сумасшедшей вещью.Я думаю, вам придется с этим смириться или вы можете создать дочерний процесс вместо AppDomain, если вам действительно нужен такой отказоустойчивый тип.

1 голос
/ 22 февраля 2011

Полагаю, проблема в том, что вы вызываете метод, вызывающий исключение из основного домена AppDomain, то есть вы вызываете какой-то метод в основном AppDomain, этот метод вызывает проблемный метод из дочернего AppDomain.Исключение возрастает в дочернем AppDomain, но распространяется по стеку вызовов к вызывающему AppDomain (основному AppDomain).Попробуйте вызвать этот метод из дочернего AppDomain полностью.Например, порождайте поток в дочернем AppDomain, чтобы этот поток вызывал проблемный метод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...