Partager via


Unloading an Assembly

There's no way to unload an individual assembly without unloading all of the appdomains containing it. (See here for why not.) This can by done by calling AppDomain.Unload() for each AppDomain that has it loaded. (You could also use UnloadDomain() on the v1 unmanaged hosting API, but in general, I recommend using managed code whenever possible.)

I should point out that this means that even if your managed Assembly/Module/etc. instances go out of scope, GC may clean those instances up. The actual file will remain loaded until you unload all of the appdomain(s) containing it, however. (In general, that's better, anyway. Loading a file, especially by http, is too expensive to be done over and over when it can just be cached.)

If you want to unload some assemblies but not others, consider creating a new AppDomain (requires ControlAppDomain permission), execute the code using the temporary ones from within that AppDomain, and then unload that new AppDomain when you're done. I recommend minimizing the number of AppDomains, though, since there is overhead involved in creating them, transitioning between them, and unloading them. So, it's best if you do all of that work at once, in one AppDomain, minimizing the cross-domain communication, and just unload that when possible (as opposed to creating a new AppDomain for each assembly to unload, etc.).

Gotchas
Watch out for references to that assembly leaking to other appdomains. If that happens, that assembly will remain loaded if you just unload one AppDomain. For example, passing a Type object to another appdomain will cause its assembly to be loaded there.

Calling Unwrap()/AppDomain.CreateInstanceAndUnwrap()/etc. may also cause the runtime to try to load the assembly in the calling appdomain. In that case, call CreateInstance*() on a MarshalByRefObject type from a different assembly. For example, using AppDomain.CreateInstanceFrom() on the calling assembly (the one currently calling Unwrap()) may be the most convenient way. Then, call a method on it which will do all of your assembly loading. That way, those assemblies can be loaded in just the target appdomain.

Also, note that assemblies loaded as domain neutral will not be unloaded until the process exits, since other appdomains are technically still using them.

Alternatives
But, maybe you don't need to load that Assembly, anyway. If you just need info about it, you could call AssemblyName.GetAssemblyName() with the path to the file. That will temporarily load the file to get the info and then immediately unload it. That call will not cause it to show up as an Assembly in the AppDomain.

Or, if you're only worried about keeping the file locked, you could use shadow copying. That will make a copy of the file on disk and load it from the new location. The original file will not be locked by that load.  To do that, set AppDomainSetup.ShadowCopyFiles to "true" when creating the AppDomain or set AppDomain.ShadowCopyFiles to true after it's already been created.

Comments

  • Anonymous
    July 08, 2003
    Hello,As you mentioned file shadowing can keep the originals unlocked, however what if we need the process entry assembly unlocked? How does one enable shadowing on the default application domain; so that the entry assembly is shadowed not just subsequent assembly loads? The app config file doesn’t seem to have any settings related to this. It seems it should be possible. Thank You

  • Anonymous
    July 08, 2003
    suzanne, How more a read how less a understand .Can you give a explantion about AppDomain's.I have made my own Mpp.Wsis.Mod_sys.ddl with Namespace Mpp.Wsis.Mod_sysin the dll is a class named public class Task.........i put the dll in the gac but when i make a sentence like these in asp.net :dim a = new Mpp.Wsis.Mod_sys.Task()there is a error, need a AppDomain's to use the class?thanks for your time

  • Anonymous
    July 09, 2003
    Can you somehow specify files in addition to the assembly to be shadow copied as well? What if you have a config file that needs to be in the same directory as the shadow copied assembly, how would you get the config file copied to the shadow directory that the assembly was copied to?

  • Anonymous
    July 09, 2003
    Marek: To enable shadow copying on the default AppDomain, you can set AppDomain.ShadowCopyFiles to true on it. But, that won't help for the process exe, since it's loaded directly by the OS, not us. (Since the OS is the one holding the lock, it being shadow copied and then reloaded from there will just mean that there are two locked copies.) If you need the original exe to not be locked, you'll have to make a copy and call that instead. Michael: I'd need to know what the exact error message was. However, probably the answer you want is at http://blogs.msdn.com/suzcook/archive/2003/05/29/57120.aspx . ASP.NET already creates an AppDomain for you, so I imagine that you won't need to create another one for your purposes. Phil: I've already answered your question at http://blogs.msdn.com/suzcook/archive/2003/06/26/57198.aspx#comments .

  • Anonymous
    July 10, 2003
    The comment has been removed

  • Anonymous
    July 10, 2003
    Yes, that's an option for some cases, but too disadvantageous for others. It puts the assembly in neither the Load nor the LoadFrom context. See my blog entry at http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx for details about the advantages and disadvantages of that. I wonder what you mean about creating an AppDomain being difficult, though. Just creating one is as easy as calling AppDomain.CreateDomain(). Instructions for using a new AppDomain are described in http://blogs.msdn.com/suzcook/archive/2003/06/12/57169.aspx .

  • Anonymous
    July 11, 2003
    Yes, creating an App domain is simple in itself. But since this is an add-in for the IDE, I would have had to duplicate the IDE's app domain, and no matter how hard I tried, I could never get it right.

  • Anonymous
    July 11, 2003
    BTW, for this addin, I only needed to do a bit of reflection on the assembly to get it's type information (classes, enums, methods, ect) and output it to an XML file. I'm never actually using the assembly for anything.

  • Anonymous
    July 11, 2003
    I'm not sure what you mean by being unable to duplicate that AppDomain. Since all you care about is reflection, you may only care about the AppDomainSetup being same (pass in AppDomain.CurrentDomain.SetupInformation)...unless you're depending on the order dependence of the LoadFrom context, or on the AssemblyResolve callback. I'd recommend against relying on those, anyway (see http://blogs.msdn.com/suzcook/archive/2003/05/29/57143.aspx ). But, if you still decide that loading by byte[] is better, keep in mind that reflection will load its dependencies. So, if its dependency is a file that you don't want locked, if it's in the Load context, it will be loaded automatically, without raising the AssemblyResolve event, even if you've already loaded it by byte[].

  • Anonymous
    July 11, 2003
    >> I'm not sure what you mean by being unable to duplicate that AppDomain. Since all you care about is reflection, you may >> only care about the AppDomainSetup being same (pass in AppDomain.CurrentDomain.SetupInformation)...I tried using the CurrentDomain.SetupInformation, but still ran into problems loading the assembly (it could never be found, even when I gave it the full path in the Load/LoadFrom. One thing that I could not get correct was to modify the PrivateBinPath to include all my assembly paths. I'm going to be working in that code again this weekend, so I may give it another shot.>> better, keep in mind that reflection will load its dependencies. So, if its dependency is a file that you don't want locked, if it's >> in the Load context, it will be loaded automatically, without raising the AssemblyResolve event, even if you've already loaded >> it by byte[].Really? I was not aware of that. I'll have to try a few tests and see what happens with my dependencies and if they get locked. The probelm is that under the IDE, assemblies loaded in an AddIn are loaded into the IDE's AppDomain, and if I load a projects assembly, it gets locked, and I can never build the project again until I shut down the IDE and restart it.

  • Anonymous
    July 14, 2003
    The comment has been removed

  • Anonymous
    July 16, 2003
    Is there any way to enable ShadowCopy on the current app domain? I am trying to load, using CreateInstanceAndUnWrap, an assembly that I would like shadow copied. I want to do this within the current app domain.. Thanks.- Mike

  • Anonymous
    July 17, 2003
    Roy: See http://blogs.msdn.com/suzcook/archive/2003/05/29/57120.aspx for advice about debugging assembly loading problems. Try looking at the paths that were probed for this file in the Fusion log. About the byte[] thing: this can be worked around by changing the assembly identity (changing the assembly version for each build). That will cause it to be reloaded, and will avoid the problems caused by using byte[] assemblies. Dejan: Thanks! I've forwarded your first question to our perf team, and will let you know. For the rest, that message sounds like a resource file is missing or corrupt. Did you try a reinstall? Plus, which resource is it asking for? Usually, this would come up while retrieving an error message (so there may be some other problem besides being unable to find the resource). Mike: Yes, set ShadowCopyFiles to true on that AppDomain instance.

  • Anonymous
    July 17, 2003
    Dejan: Rico, from our perf team, had this to say:It's really very difficult to say what's happened here with any kind of accuracy. Often if there is a great deal of heap usage you can trace it to live objects that are staying live much longer than they need to. The creation of an appdomain in this customer's scenario could be causing some domain neutral assemblies to be loaded which are not then unloaded. And, of course, there's the question of what the code itself does and how much of it lives and for how long.I don't know what guidance I can give you overall other than:-look into the key performance counters for the GC (really logging all of them can be useful), and-use CLRProfiler to see what's really being allocated and when and then use that to drive modifications .Really, the trouble is that it's easy for people to inadvertantly ask for services that will require large swaths of memory. It's very easy to then just assume it's because .NET is fat, but at the core the CLR doesn't do allocations on the order of magnitude that this person is seeing. He's activated some hefty framework pieces somehow - the question is, which and how.

  • Anonymous
    July 18, 2003
    Thanks for the info. My problem is that I need to dynamically load assemblies into either the current appdomain with Shadow Copyiing enabled, but when I turned it on, Shadow Copying did not occur. I read in the MSDN that you couldn't set this after the "first binding" had occured, but I was not sure what that was. I created a new app domain and have shadow copying working on that, but when I try and load certain assemblies, I get a "Cannot find assembly" error. However, I KNOW that it is finding it, as the constructor for the class I am trying to load indeed runs. As soon as the constructor completes, the exception is raised. Any help is MUCH appreciated. FYI - what we're doing here is running C# .NET forms as MDI children of a VB 6 project, and we almost have it working.

  • Anonymous
    July 20, 2003
    I should have said to call AppDomain.CurrentDomain.SetShadowCopyFiles() - ShadowCopyFiles is a getter property, with no setter. Where is that doc? It needs to be corrected - you can set it, and it will take effect, even after the first binding (the first assembly load in that appdomain). Just don't bother setting it on the AppDomainSetup for an AppDomain after that AppDomain has already been created - it will have no effect. It sounds like a dependency of that assembly is failing to load. See http://blogs.msdn.com/suzcook/archive/2003/05/29/57120.aspx for debugging advice.

  • Anonymous
    July 21, 2003
    Thanks again for the info. I'd certainly like to NOT have to create a new AppDomain, since that creates it's own set of problems for me. I can't find any examples of enabling ShadowCopy on the current app domain, but this is what I am doing:AppDomain.CurrentDomain.SetShadowCopyPath(this.m_probePath);AppDomain.CurrentDomain.SetShadowCopyFiles();this.m_probePath contains the directory of the assemblies I want to shadow copy. But, my application base is actually the directory of the VB 6 application.. All the assembly loads fail as it claims that it cannot find the assemblies. How do I make it recognize m_probePath as the source for my assemblies? Thanks again.

  • Anonymous
    July 21, 2003
    The comment has been removed

  • Anonymous
    July 21, 2003
    Mike: SetShadowCopyPath() is not like specifying an extra ApplicationBase - those assemblies will need to be find-able in the normal way. (You may want to consider creating a new AppDomain with m_probePath as the ApplicationBase, and run your code from there - see http://blogs.msdn.com/suzcook/archive/2003/06/12/57169.aspx .) SetShadowCopyPath() will just make it so that only those dirs will have assemblies shadow-copied from there, not all dirs. Dejan: This is getting to be specific enough to you that it's better if I just follow up over email on both issues.

  • Anonymous
    July 22, 2003
    Thanks for the clarification on SetShadowCopyPath() - the MSDN docs are not entriely clear on this. When I use another AppDomain, I run into the other problem I presented earlier, where certain assemblies do not load. I will go back and follow your advice on trying to determine why these assemblies error immediately after the contructor of the class I am creating runs. It's very strange. Thanks for the assistance.

  • Anonymous
    June 14, 2004
    I wanted to use c# to copy some of the functionallity on the Unreal Engine, where the level designer can recompile the script source for an object(actor), recompile the script, and use it again in the UnrealEd.... the problem is that I CAN'T unload my previous version of "the object" to replace it for the new one ... I tryed to use a different AppDomain to load/unload "the object", but got multiple serialization/marshaling exceptions ... now the exceptions are solved, but the use os multiple domains has BRUTAL overhead....

  • Anonymous
    May 27, 2005
    Speaking of dynamic IL generation ...
    Before Whidbey, the framework supplied two ways of creating code...

  • Anonymous
    September 27, 2005
    Suzanne,

    You've mentioned that it's possible to call AppDomain.CurrentDomain.SetShadowCopyFiles to enable shadow copying on the current AppDomain.

    However, I notice in .Net 2.0 this method is marked as obsolete. The documentation suggests that we should be creating a new AppDomain and using AppDomainSetup.ShadowCopyFiles. Should I really be doing this in .Net 1.1 as well? Is there a real reason for SetShadowCopyFiles now being obsolete, or is it just that it's not the preferred way of doing things?

    Thanks,
    Steve.

  • Anonymous
    July 29, 2006
    Introduction
    The last couple of days I've been playing around with some stuff around WCF (formerly known...

  • Anonymous
    October 23, 2007
    I am developing an addin which reads when clicked retrieves modules and their field information in the project assembly. Inorder to do this I am creating an application domain and trying to load the project assembly so that I can retrieve all modules in the assembly using getloadedmodules method. I am having problem in loading the assembly. when I try to load the assembly it is throwing an error related either fileiopermissionaccess failed or securitypermission failed. I am new to .net and I am currently using .net 2003. Can any one suggest an alternative to this. Thanks.

  • Anonymous
    August 01, 2008
    The comment has been removed

  • Anonymous
    October 21, 2008
    Hi, I'm dynamically loading an assembly in a new AppDomain in order to list the types it ccontains, after that the assembly is removed via the unload of the AppDomain. I use a proxy class to load and reflect the assembly. The reflection happens in a sharepoint context. So far the facts. When I recompile the assembly (after adding or removing types) that I am reflecting on and store it in the GAC the change in types is not 'reflected'. If I remove the assembly from the GAC I receive an error the the assembly can not be found, if it finds the assemblty it is still the previous version. If I do an application pool recycle the changes are reflected. So it seems that even though the assmbly is unloaded (I can verify that it never has been loaded in the main appdomain by looking at AppDomain.CurrentDomain.GetAssemblies()) it still hangs around somewhere. Anyone has any idea? Thanks in advance, Wilke

  • Anonymous
    October 12, 2010
    Hi, I want to know is there any limit for loading assembly in one AppDomain, bcos i m planning to generate assembly runtime depends on my user's input so every time i will generate new assembly and load into current domain. Thanks in Advance.