AppDomain.Unload在Finalizer中抛出异常?

8

以下是目前的情况,我有一个使用AppDomain执行某些任务的工作程序。该域的设置和拆除非常昂贵。因此,我为每个线程创建了一个弱引用对象的缓存来维护工作程序,就像这样:

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
}

我遇到的问题是,当垃圾回收时,调用AppDomain.Unload总是会抛出异常:
System.CannotUnloadAppDomainException: Error while unloading appdomain. (Exception from HRESULT: 0x80131015)"

我认为这很奇怪,因为我知道在该域中没有任何东西在“运行”... 怎么回事? 经过一番挖掘和尝试,我得出了以下结论:

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

所以我的问题是:

  1. 从终结器中卸载AppDomain是否总是失败?为什么?
  2. 我会在上述解决方法中遇到任何“不良”情况吗?

可能是为什么AppDomain.Unload()在终结器中出错?的重复问题。 - Fabian
1个回答

13

AppDomains被一个单独的CLR线程卸载。当终结器线程正在运行时,该线程无法运行。您之所以收到异常是因为CLR注意到卸载线程没有取得进展。由于终结器线程被阻塞在Unload调用上,因此它永远不会开始。

死锁。

您的解决方法确实解决了这个死锁问题。在这里,显式卸载而不是依赖于终结器是更好的方法。


啊,正如我所料。同意显式卸载会更好;然而,我没有一个可以卸载缓存域的地方。这就是使用WeakReference的原因。 - csharptest.net
我们刚刚在将项目升级到.NET 4之后开始遇到这个问题。对于我们来说,3.5 SP1似乎没有出现这种行为。不过,我能理解这个答案的逻辑,所以很愿意修复我们的错误代码。 - nbevans

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接