我有一个应用程序,它加载外部程序集,我无法控制这些程序集(类似于插件模型,其他人创建和开发的程序集由主应用程序使用)。 它通过为这些程序集创建新的AppDomain来加载它们,然后当使用完这些程序集时,主AppDomain会卸载它们。
目前,它以简单的方式卸载这些程序集:
try
{
AppDomain.Unload(otherAssemblyDomain);
}
catch(Exception exception)
{
// log exception
}
然而,有时在卸载过程中会发生异常,具体来说是CannotUnloadAppDomainException
。据我所知,这可以预料到,因为子应用程序域中的线程无法被强制中止,因为仍在执行非托管代码或线程处于finally
块中:
当线程调用Unload时,目标 域会被标记为要卸载。专用线程尝试卸载 域,域中的所有线程都将被终止。如果线程没有 终止,例如因为它正在执行非托管代码,或者因为 它正在执行finally块,则 在一段时间后,将在最初调用Unload的线程中引发 CannotUnloadAppDomainException。如果无法中止的线程最终结束, 目标域不会被卸载。 因此,在.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;
}
}
这有意义吗?我是否应该再次尝试卸载?还是只尝试一次然后继续进行?还有,如果线程仍在运行,是否可以从主AppDomain执行某些操作来控制外部程序集(请记住其他人正在编写和运行此外部代码)?
我正在尝试了解管理多个AppDomains的最佳实践。