我有一个加载外部程序集的应用程序,我无法控制这些程序集(类似于其他人创建和开发主应用程序使用的程序集的插件模型)。它通过为这些程序集创建新的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条答案
按热度按时间xwbd5t1u1#
我在我的应用程序中处理过类似的问题,基本上,你不能做任何比
Unload
更多的事情来迫使AppDomain
关闭。它基本上调用了正在
AppDomain
中执行代码的所有线程的abort,如果该代码停留在终结器或非托管代码中,则没有什么可做的。如果根据所讨论的程序,终结器/非托管代码可能会在稍后完成,则完全可以再次调用
Unload
;如果不是,则可以故意泄漏域或循环该进程。gblwokeq2#
如果不卸载域,请尝试使GC.Collect()。
chhqkbe13#
我有类似的问题与随机行为几个月了,现在,(与一些应用程序。卸载甚至阻止永远!在一些机器上)终于决定采取一个大呼吸,使进程隔离。你可以产生子控制台进程和重定向输出
如果你需要取消,这是在鼻子上的手指杀死子进程和所有的依赖/句柄。
在极端情况下,我不得不运行专门的清理代码,并来到解决方案,以创建额外的进程与专用的cmd行等待输入提取的控制台输出的初始运行程序进程。
是的,这个应用程序域是一个真实的的笑话,我认为这不是一个巧合,它不再是在net核心。