Как правильно выгрузить AppDomain с помощью C #? - PullRequest
22 голосов
/ 13 декабря 2010

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

В настоящее время упрощенно выгружает эти сборки

try
{
    AppDomain.Unload(otherAssemblyDomain);
}
catch(Exception exception)
{
    // log exception
}

Однако иногда в процессе выгрузки возникают исключения, в частности CannotUnloadAppDomainException. Насколько я понимаю, этого можно ожидать, поскольку поток в дочерних доменах приложений нельзя принудительно прервать из-за ситуаций, когда неуправляемый код все еще выполняется или поток находится в блоке finally :

Когда поток вызывает Unload, цель домен помечен для выгрузки. выделенный поток пытается выгрузить домен, и все темы в домен прерван. Если поток делает не прерывать, например, потому что это выполнение неуправляемого кода, или потому что он выполняет блок finally, затем через некоторое время CannotUnloadAppDomainException is бросил в ветке, что изначально называется Unload. Если нить то не может быть прервана в конце концов, целевой домен не выгружен. Таким образом, в версии .NET Framework Домен 2.0 не гарантированно выгружен, потому что это может быть можно прекратить выполнение резьб.

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

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

try
{
    AppDomain.Unload(otherAssemblyDomain);
}
catch (CannotUnloadAppDomainException exception)
{
    // log exception
    var i = 0;
    while (i < 3)   // quit after three tries
    {
        Thread.Sleep(3000);     // wait a few secs before trying again...
        try
        {
            AppDomain.Unload(otherAssemblyDomain);
        }
        catch (Exception)
        {
            // log exception
            i++;
            continue;
        }
        break;
    }
}

Имеет ли это смысл? Должен ли я вообще пытаться разгрузиться снова? Должен ли я просто попробовать один раз и двигаться дальше? Есть ли что-то еще, что я должен сделать? Кроме того, можно ли что-нибудь сделать из основного домена приложений для управления внешней сборкой, если потоки все еще работают (имейте в виду, что другие пишут и выполняют этот внешний код)?

Я пытаюсь понять, как лучше всего управлять несколькими доменами приложений.

Ответы [ 2 ]

10 голосов
/ 03 мая 2011

Я столкнулся с подобной проблемой в своем приложении.По сути, вы не можете сделать что-то большее, чтобы заставить AppDomain выйти из строя, чем Unload.

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

Если, основываясь на рассматриваемой программе, вполне вероятно, что финализатор / неуправляемый код завершит работу позжеможет абсолютно позвонить Unload снова.Если нет, вы можете либо намеренно утечь домен, либо завершить процесс.

0 голосов
/ 07 февраля 2017

Попробуйте сделать GC.Collect (), если не выгружаете домен.

 try
    {
       AppDomain.Unload(otherAssemblyDomain);
    }
    catch (CannotUnloadAppDomainException)
    {
       GC.Collect();
       AppDomain.Unload(otherAssemblyDomain);
    }
...