Why isn't there an Assembly.Unload method?

Why isn't there an Assembly.Unload method?

Rate This
  • Comments 60

We frequently get asked why you cannot unload an assembly from an app domain.  After all, you can do a FreeLibrary() in unmanaged code to unload a DLL, and the CLR is just using DLL's right?

Reasons to Want to Unload

There are generally two reasons that you want to unload an assembly:  space and versioning.  The former is obvious, you want to free up allocated memory in the process.  The second refers to wanting to load a newer version of an assembly, as for example Asp.Net does when you compile a new version of your application.  If the assembly's underlying file is locked in the file system, you cannot replace it.

Why Not Support It?

There are a few problems with unloading an individual assembly, some of them hard design issues and some of them just work:

1.  First off, you are running that code in the app domain (duh!).  That means there are potentially call sites and call stacks with addresses in them that are expecting to keep working.  Have you ever gotten an access violation where your EIP points to 0x????????  That is an example where someone freed up a DLL, the pages got unmapped by the memory system, and then you tried to branch to it.  This typically happens in COM when you have a ref counting error and you make an interface method call.  We cannot afford to be as lose with managed code.  We must guarantee we know all of the code you are executing and that it is type safe and verifiable.  That means explicit tracking of anything that could be using that code, including GC objects and COM interop wrappers.  This tracking is handled today around an app domain boundary.  Tracking it at the assembly level becomes quite expensive.

2.  Say you did manage to track all handles and references to already running code by an assembly.  Assuming you didn't ngen the code, once you successfully freed up the assembly, you have only freed up the metadata and IL.  The JIT'd code is still allocated in the app domain loader heap (JIT'd methods are allocated sequentially in a buffer in the order in which they are called).  Now we do know the identity of all methods, so we could go back and track down all of the code and turn the heap into a malloc style heap with a free list (in fact we had a code pitching jitter we prototyped way back when on Windows CE that did precisely this to limit the overall JIT heap size).  So this one is solvable and just falls into the work column with a small hit on allocation and jitted method locality (probably not enough to measure).

3.  The final issue relates to code which has been loaded shared, otherwise more formally know as "domain neutral" (check out /shared on the ngen tool).  In this mode, the code for an assembly is generated to be executed from any app domain (nothing hard wired).  This has some interesting trade offs:  on the one hand you can execute the same code in any app domain so it loads faster in subsequent app domain instances (its already there).  On the other hand, the code must therefore be tracked in all app domains it has ever been loaded into before it can be freed.  With the current v1.0 and v1.1 product it is not even possible to unload domain neutral code because of these restrictions.

In the end you should be getting the flavor that this is not an impossible feature to implement, but is also non-trivial.  In essence, we have already built in the design around the notion of an app domain and amortized it across all assemblies, hence the model.  I will not rule out having such a feature in the future.  But it is not planned for the Whidbey product at this time.

So What's the Alternative?

It is recommended that you design your application around the application domain boundary naturally, where unload is fully supported.  For example, Asp.Net hosts applications in an app domain and unloads them when they are no longer needed or out of date.  SQL Server Yukon does the same thing for SQL/CLR.  In addition, you can use the Shadow Copy feature of Fusion to avoid the file in use locking error (also used by Asp.Net).  The added advantage of this model is that you can write your host to monitor and abort app domains which engage in bad behavior (such as using too much memory or resources).  This can be very helpful when you are hosting potentially un-trusted or potentially less robust code. 

If there is interest, I have been considering posting a hosting sample which does app domain recycling policy as this does come up quite a bit...

  • Jason, to be honest this SUCKS BIG TIME. Whatever the technical difficulties are you should try and get them resolved. We are not going turn our app into a big mess and debug app domain leaks (to anyone planning to architect apps around app domains: don't even think about it). Instead we decided to cut the add-in feature we wanted to do and we are telling our users that this is not possible with the .NET Framework.
  • Also, thanks a lot for explaining this. It helps a lot to know this won't be repaired anytime soon.
  • I agree this is one of the biggest flaws in .NET design. We also chose not to use .NET for a project because of this.
  • If you really want to take the overhead hit of being able to load/unload single assemblies at a time, just write a simple wrapper class which manages the assembly -- loading, getting a reference to the assembly, and unloading it. The wrapper class would be responsible for creating the AppDomain on the fly and destroying it when you wanted to 'unload' the assembly.

    This isn't hard stuff folks.

    Managing assemblies you want to unload in AppDomains actually makes things easier in some respects, depending on your application model.
  • I can see a lot of good passion around this one <g>

    Francis - I'd like to understand your concerns more. In particular for an add-in model, the app domain model should be ideal. For example, if I were going to host managed code in Outlook, I'd want to do it in an app domain where I could also lower the CAS permissions so that, for example, I could prevent add-in code from touching my address book and spawning a Melissa virus. What is it about app domains that bugs you? If we either gave a really great sample or even built some hosting into the CLR (think thread pool for app domains) would that help alleviate concerns?

    As mirobin suggests, you can abstract pieces of this too. the one piece of the programming model that does get exposed in this case is inter-app domain remoting. So depending on how you want to program against your objects you may need to inherit from MarshalByRef.
  • Jason,

    I use multiple appdomains all the time and I think it has worked out fairly well, but there are some issues and limitations. Hosting plugins in separate appdomains becomes difficult is there is extensive communication between the host and the plugin due to the remoting boundary. I'm also told that some limitations wont be resolved until Whidbey, such as the transitive loading of assemblies using custom evidence (e.g. different security zone), but right now it is a security hole.

    Right now I am trying to figure out how to use different binding redirects for each appdomain using app config files. Can this be done in v1.1? In other words, is there a way to have different appdomains use a different binding redirect policy for the same assembly?

  • I am writing a windows forms application that will house multiple MDI children applications each in their own assembly. These MDI children are loaded dynamically. I would like to be able to unload an assembly so that I can bring in a new version without having to take down the whole parent application. I have attempted to put the MDI child in a separate appdomain but this is not possible due to WinForms serialzation problems. An Assembly.Unload would be very helpful to me.
  • In my attempts to get CodeSmith templates to execute in another AppDomain, I basically ran into a brick wall because it was either impossible or just a TON or work to get an object in another AppDomain to be the selected object in a PropertyGrid instance. If anyone knows of a way to do this, please contact me and let me know. Here is a link to more information about the problem I am having:
    http://weblogs.asp.net/ericjsmith/archive/2004/05/06/127185.aspx
  • Jazon Zander skriver om, hvorfor der
    ikke findes en Assembly.Unload metode.
    Vi lavede nemlig en arkitektur...
  • The thing that absolutely sucks is that cross-appdomain calls are uselessly slow. See the results I posted at www.jelovic.com/weblog/e87.htm to see how bad the situation is.

    Any plans to fix that?
  • I would love to see an application sample.

    thanks
  • Another "workaround" is Light Weight Codegen in Whidbey. Hopefully, in the future Light Weight Codegen will also support creating types, that would really be nice work around.

    Using AppDomains is not an option for perf critical stuff.
Page 1 of 4 (60 items) 1234