AppDomain.Unload throws in Finalizer?
Asked Answered
R

1

8

So here is the story so far, I have this worker thingy which uses an AppDomain to perform some task. The domain is expensive to setup and teardown. So I create a cache per-thread of WeakReference objects to the worker thingy like so:

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
}

The problem I'm having is that seems to always throw an exception in the call to AppDomain.Unload when GC collects:

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

So I'm thinking that's wierd, I know I don't have anything 'running' in that domain... Whats the deal? A bit of digging and trial and error I came up with this:

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

So my Questions are:

  1. Will AppDomain.Unload always fail from a Finalizer? Why?
  2. Am I going to experience anything 'undesirable' with the above workaround?
Robbert answered 31/10, 2010 at 19:34 Comment(1)
Possible duplicate of Why does AppDomain.Unload() error in finalizer?Cosmopolite
C
13

AppDomains are unloaded by a separate CLR thread. That thread cannot run while the finalizer thread is running. You're getting the exception because the CLR notices that the unload thread isn't making progress. It never gets going because the finalizer thread is blocked on the Unload call.

Deadlock.

Your workaround indeed solves that deadlock. Doing the unloading explicitly instead of relying on a finalizer is the better approach here.

Claus answered 31/10, 2010 at 20:7 Comment(2)
Ahh, as I suspected. Agreed that the explicit unload would be better; however, i don't have a place from which I can unload the cached domains. That was the reason for the WeakReference.Robbert
We've just started getting it after upgrading the project to .NET 4. 3.5 SP1 didn't seem to have this behaviour for us. I can understand the logic in this answer though so am happy to fix our broken code.Chukar

© 2022 - 2024 — McMap. All rights reserved.