【发布时间】:2011-05-24 20:18:47
【问题描述】:
我有一个应用程序加载我无法控制的外部程序集(类似于插件模型,其他人创建和开发主应用程序使用的程序集)。它通过为这些程序集创建新的 AppDomain 来加载它们,然后在使用完这些程序集后,主 AppDomain 会卸载它们。
目前,它简单地unloads这些程序集由
try
{
AppDomain.Unload(otherAssemblyDomain);
}
catch(Exception exception)
{
// log exception
}
但是,有时在卸载过程中会抛出异常,特别是CannotUnloadAppDomainException。据我了解,这是可以预料的,因为子 AppDomains cannot be forcibly aborted due to situations where unmanaged code is still being executed or the thread is in a finally block 中有一个线程:
当一个线程调用Unload时,目标 域被标记为卸载。这 专用线程尝试卸载 域,以及域中的所有线程 域被中止。如果一个线程做 不中止,例如因为它是 执行非托管代码,或者因为 它正在执行 finally 块,然后 一段时间后 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 控制外部程序集?
我正在尝试了解管理多个 AppDomain 时的最佳做法。
【问题讨论】:
-
这是无法回答的。如果您无法控制应用程序中的线程,那么没有理由希望其中一个线程会在 3 秒后突然合作。将其隔离在一个进程中是唯一真正的解决方法。
-
谢谢汉斯。与进程相比,这听起来像是 AppDomains 的限制。我希望有一种方法可以在任何情况下强制终止 AppDomain,就像您可以强制终止进程(如您所建议的那样)。
-
@HansPassant 将执行隔离到专用进程真的可以避免这种情况吗?