AppDomain.Unload 抛出终结器?

Posted

技术标签:

【中文标题】AppDomain.Unload 抛出终结器?【英文标题】:AppDomain.Unload throws in Finalizer? 【发布时间】:2010-10-31 19:34:56 【问题描述】:

这就是目前为止的故事,我有一个使用 AppDomain 执行某些任务的工作人员。该域的设置和拆卸成本很高。因此,我为工作人员创建了每个线程的 WeakReference 对象缓存,如下所示:

class Worker

    [ThreadStatic]
    static Dictionary<string, WeakReference> _workers;

    public static Worker Fetch( ... )  you get the idea 

    private AppDomain _domain;
    public Worker(...)
    
        _domain = AppDomain.Create( ... );
    

    ~Worker()
     
        AppDomain.Unload(_domain);
    

    // bla bla bla

我遇到的问题是,当 GC 收集时,似乎总是在调用 AppDomain.Unload 时抛出异常:

System.CannotUnloadAppDomainException: Error while unloading appdomain. (Exception from HRESULT: 0x80131015)"

所以我认为这很奇怪,我知道我在该域中没有任何“正在运行”的东西......有什么关系?经过一番挖掘和反复试验,我想出了这个:

    ~Worker()
     
        new Action<AppDomain>(AppDomain.Unload)
            .BeginInvoke(_domain, null, null);
    

所以我的问题是:

    AppDomain.Unload 是否总是从终结器失败?为什么? 使用上述解决方法我会遇到任何“不受欢迎”的事情吗?

【问题讨论】:

Why does AppDomain.Unload() error in finalizer?的可能重复 【参考方案1】:

AppDomain 由单独的 CLR 线程卸载。当终结器线程正在运行时,该线程无法运行。您收到异常是因为 CLR 注意到卸载线程没有取得进展。它永远不会继续,因为终结器线程在 Unload 调用上被阻塞。

死锁。

您的解决方法确实解决了这个僵局。明确地进行卸载而不是依赖终结器是这里更好的方法。

【讨论】:

啊,正如我所怀疑的那样。同意显式卸载会更好;但是,我没有可以卸载缓存域的地方。这就是 WeakReference 的原因。 在将项目升级到 .NET 4 后,我们才刚刚开始获得它。3.5 SP1 似乎对我们没有这种行为。我可以理解这个答案中的逻辑,所以很高兴修复我们损坏的代码。

以上是关于AppDomain.Unload 抛出终结器?的主要内容,如果未能解决你的问题,请参考以下文章

AppDomain.Unload() 如何中止线程?

.NET AppDomain.Unload 触发失控线程

进程和 AppDomain 加载/卸载

即使我卸载 appdomain,我的 dll 也不会卸载

assembly 需要 unload 和 update 的时候怎么办?

Python 终结者 - 装饰器,也叫 Decorator