Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly unload an AppDomain using C#?

Tags:

I have an application that loads external assemblies which I have no control over (similar to a plugin model where other people create and develop assemblies that are used by the main application). It loads them by creating new AppDomains for these assemblies and then when the assemblies are done being used, the main AppDomain unloads them.

Currently, it simplistically unloads these assemblies by

try {     AppDomain.Unload(otherAssemblyDomain); } catch(Exception exception) {     // log exception } 

However, on occasion, exceptions are thrown during the unloading process specifically CannotUnloadAppDomainException. From what I understand, this can be expected since a thread in the children AppDomains cannot be forcibly aborted due to situations where unmanaged code is still being executed or the thread is in a finally block:

When a thread calls Unload, the target domain is marked for unloading. The dedicated thread attempts to unload the domain, and all threads in the domain are aborted. If a thread does not abort, for example because it is executing unmanaged code, or because it is executing a finally block, then after a period of time a CannotUnloadAppDomainException is thrown in the thread that originally called Unload. If the thread that could not be aborted eventually ends, the target domain is not unloaded. Thus, in the .NET Framework version 2.0 domain is not guaranteed to unload, because it might not be possible to terminate executing threads.

My concern is that if the assembly is not loaded, then it could cause a memory leak. A potential solution would be to kill the main application process itself if the above exception occurs but I rather avoid this drastic action.

I was also considering repeating the unloading call for a few additional attempts. Perhaps a constrained loop like this:

try {     AppDomain.Unload(otherAssemblyDomain); } catch (CannotUnloadAppDomainException exception) {     // log exception     var i = 0;     while (i < 3)   // quit after three tries     {         Thread.Sleep(3000);     // wait a few secs before trying again...         try         {             AppDomain.Unload(otherAssemblyDomain);         }         catch (Exception)         {             // log exception             i++;             continue;         }         break;     } } 

Does this make sense? Should I even bother with trying to unload again? Should I just try it once and move on? Is there something else I should do? Also, is there anything that can be done from the main AppDomain to control the external assembly if threads are still running (keep in mind others are writing and running this external code)?

I'm trying understand what are best practices when managing multiple AppDomains.

like image 213
Ray Avatar asked Dec 13 '10 18:12

Ray


People also ask

How do you unload assembly from AppDomain?

You can not unload an assembly from an appdomain. You can destroy appdomains, but once an assembly is loaded into an appdomain, it's there for the life of the appdomain.

How do I unload an assembly in powershell?

To unload an assembly in the . NET Framework, you must unload all of the application domains that contain it. To unload an application domain, use the AppDomain. Unload method.

What is AppDomain C#?

The AppDomain class implements a set of events that enable applications to respond when an assembly is loaded, when an application domain will be unloaded, or when an unhandled exception is thrown. Advantages. A single CLR operating system process can contain multiple application domains.

What is AppDomain and CurrentDomain?

The CurrentDomain property is used to obtain an AppDomain object that represents the current application domain. The FriendlyName property provides the name of the current application domain, which is then displayed at the command line.


1 Answers

I've dealt with a similar problem in my app. Basically, you can't do anything more to force the AppDomain to go down than Unload does.

It basically calls abort of all threads that are executing code in the AppDomain, and if that code is stuck in a finalizer or unmanaged code, there isn't much that can be done.

If, based on the program in question, it's likely that the finalizer/unmanaged code will finish some later time, you can absolutely call Unload again. If not, you can either leak the domain on purpose or cycle the process.

like image 117
aL3891 Avatar answered Oct 09 '22 16:10

aL3891