none
Question about using an AppDomain to allow a COM DLL to be loaded and unloaded without locking the underlying file RRS feed

  • Question

  • Hi,

    I was under the impression that one of uses of an App Domain was to allow files to be loaded and subsequently unloaded by unloading the App Domain at a later time.

    What I want to be able to do is to instantiate a simple COM object and not have the underlying file that hosts the COM object be locked for the entire execution of the C# program.

    Is it incorrect to think that an AppDomain should allow this?   In the sample below, a COM object (created from a new visual studio 2008 ATL Project stub) will be loaded.  The underlying DLL that hosts the com object will be locked until the entire program is stopped rather than when the AppDomain is unloaded.

    NOTE: This is using visual studio 2008 with .Net 3.0 with a build target of x86

    Here is the code that I am using to test this.

    using

     

    System;

    using

     

    System.Collections.Generic;

    using

     

    System.Linq;

    using

     

    System.Text;

    using

     

    System.Runtime.InteropServices;

    namespace

     

    AppDomainTest

    {

     

    public class Worker : MarshalByRefObject

    {

     

    public void RemoteInstantiate ()

    {

     

    // NOTE: The guid below represents the Class ID for a new Visual Studio ATL project

     

    // ie: Start Visual Studio 2008, select New C++ Project and use the ATL Project as the template

     

    Guid uuidOfComComponent = new Guid("159A1FF3-69EF-4A25-8C8F-734FAD3FC5C0");

     

    Type type = Type.GetTypeFromCLSID(uuidOfComComponent);

     

    // Instantiate the COM component

     

    Object component = Activator.CreateInstance(type);

     

    // Now release the COM object

     

    Marshal.ReleaseComObject(component);

    }

    }

     

    class Program

    {

     

    static void Main(string[] args)

    {

    System.

    Console.WriteLine("Creating a new app domain...");

     

    AppDomainSetup ads = new AppDomainSetup();

    ads.ShadowCopyFiles =

    "true";

     

    AppDomain enumerationDomain = AppDomain.CreateDomain("NewDomain", null, ads);

     

     

    Worker worker = (Worker)enumerationDomain.CreateInstanceAndUnwrap(System.Reflection.Assembly.GetExecutingAssembly().FullName, "AppDomainTest.Worker");

    worker.RemoteInstantiate();

    worker =

    null;

     

    AppDomain.Unload(enumerationDomain);

     

    System.

    Console.WriteLine("The app domain has been unloaded.");

     

    // Wait around until a key is pressed (note: while this program is executing,

     

    // the underlying file which corresponds to the DLL loaded by RemoteInstantiate will be locked

    System.

    Console.ReadKey();

    }

    }

    }

    Friday, January 29, 2010 2:49 AM

Answers

  • AppDomain unload is not guaranteed to finish immediatelly. There are internal implementation reasons, why CLR cannot just finish it at the moment and may delay some stuff for later (even for the end of the application).
    For example some mixed-mode assemblies cannot be unloaded (e.g. if they have process-wide static variables).

    Overall AppDomains were not designed to achieve your goal to not lock files or unload AppDomains at some specific moment.

    If you need the file not being locked, just copy it into a temporary directory before you use it and load it from there. Do not load and use the master copy of your DLL which you need to change from time to time.

    -Karel
    • Proposed as answer by SamAgain Friday, February 5, 2010 6:25 AM
    • Marked as answer by SamAgain Tuesday, February 9, 2010 4:22 AM
    Friday, January 29, 2010 6:54 PM
    Moderator
  • Hi, John:

        I just want add some more comments related to AppDomain.
        One of Windows' great feature is that it can run different applications in its own process address space. This kind of isolation prevent many securty issues and make the whole system more robust. But process creation in Windows is very expensive. .NET introduces AppDomain concept, which also provide good isolation mechanism but at a much lower cost. You can configue a AppDomain extensivly. If applications are entirely written in managed code and don't call any unmanaged code, they can be run in different AppDomains within a single Windows process.
        AppDomain can be unloaded. Unloading an AppDomain causes the CLR to unload all of the assemblies in that AppDomain, and the CLR frees the AppDomain's loader heap as well. When unloading happens, the CLR perfom a lot of things to gracefully unload the specified AppDomain:
        1. The CLR suspends all threads in the process that have ever executed managed code.
        2. The CLR examines all of the threads' stacks to see which threads re currently executing code in the AppDomain to be unloaded or which threads might return at some point to code in the AppDomain to be unloaded. The CLR forces any threads that have the unloading AppDomain on their stack to throw a ThreadAbortException (resuming the thread's execution). This cause the threads to unwind, excuting any finally blocks on their way out so that cleanup code executes. If no code catches the ThreadAbortException, the CLR will swallow the unhandled exception, and the thread dies, but the process si allowed to continue running. This is unusual because for all other unhandled exceptions, the CLR will also kill the process.
        3. The CLR then walks the heap and sets a flag in each proxy objet that referred to an object created by the AppDomain to be unloaded.  These proxy objects now know that the real object they referred to is gone. If any code now calls a method on an invalid proxy object, the method will throw an AppDomainUnloadedException.
        4. The CLR forces a GC to occur, reclaiming the memory used by any objects that were created by the AppDomain to be unloaded. The Finalize methods for these objects are called, giving the objects a chance to clean themselves properly.
        5. The CLR resumes all of the remaining threads. The thread that called AppDomain.Unload will now continue running and Appomain.Unload  is called synchronously.

      
    Please mark the right answer at right time.
    Thanks,
    Sam
    • Marked as answer by SamAgain Tuesday, February 9, 2010 4:22 AM
    Friday, February 5, 2010 6:21 AM

All replies

  • AppDomain unload is not guaranteed to finish immediatelly. There are internal implementation reasons, why CLR cannot just finish it at the moment and may delay some stuff for later (even for the end of the application).
    For example some mixed-mode assemblies cannot be unloaded (e.g. if they have process-wide static variables).

    Overall AppDomains were not designed to achieve your goal to not lock files or unload AppDomains at some specific moment.

    If you need the file not being locked, just copy it into a temporary directory before you use it and load it from there. Do not load and use the master copy of your DLL which you need to change from time to time.

    -Karel
    • Proposed as answer by SamAgain Friday, February 5, 2010 6:25 AM
    • Marked as answer by SamAgain Tuesday, February 9, 2010 4:22 AM
    Friday, January 29, 2010 6:54 PM
    Moderator
  • Hi Karel,

    Thanks for this feedback. 

    What I have been struggling with is determining when it is appropriate to migrate from the notion of hosting remote objects in a separate process vs. an app domain. 

    In my original example, I could have spawned a separate process, instantiated the object, released it and then terminated the process.  Then the original (long-running) application could have remained running and the underlying DLL could have been replaced (ie: it would not be locked).

    I had a follow-on to this particular question with respect to the same scenario.  One of my other understandings regarding AppDomains was that they allowed a discrete (process-like) environment that could be unloaded and the resources allocated within the domain would be unloaded/reclaimed. 

    Using my original example, I am not observing this.  If you refer to my original example, I was simply instantiating a COM object and then releasing it and finally unloading the AppDomain that the object was created and hosted in.  If I happened to allocate a large amount of memory (say 500 MB) in the COM object, I will see the application's memory usage rise to accommodate this.  However, I would have thought that when I released the object and unloaded the AppDomain that any memory allocated in it (via the COM object) would have also been released.

    NOTE:  I purposely allocated the memory within the COM object to simulate a memory leak. 

    It was my understanding (and hope) that I could host the COM object in a separate AppDomain, and if it had memory issues, that I could insulate the main application (the C# app) from those via the separate AppDomain.

    Was this a bad assumption to make with regard to the AppDomain class (or how it should be utilized)?  It is becoming more evident to me that these types of operations are best handled in the context of a separate process (which makes me wonder if AppDomains and COM should not be mixed).

    Thanks for any information,


    -john
    • Proposed as answer by SamAgain Friday, February 5, 2010 6:25 AM
    • Unproposed as answer by SamAgain Friday, February 5, 2010 6:25 AM
    Friday, January 29, 2010 8:26 PM
  • Hi, John:

        I just want add some more comments related to AppDomain.
        One of Windows' great feature is that it can run different applications in its own process address space. This kind of isolation prevent many securty issues and make the whole system more robust. But process creation in Windows is very expensive. .NET introduces AppDomain concept, which also provide good isolation mechanism but at a much lower cost. You can configue a AppDomain extensivly. If applications are entirely written in managed code and don't call any unmanaged code, they can be run in different AppDomains within a single Windows process.
        AppDomain can be unloaded. Unloading an AppDomain causes the CLR to unload all of the assemblies in that AppDomain, and the CLR frees the AppDomain's loader heap as well. When unloading happens, the CLR perfom a lot of things to gracefully unload the specified AppDomain:
        1. The CLR suspends all threads in the process that have ever executed managed code.
        2. The CLR examines all of the threads' stacks to see which threads re currently executing code in the AppDomain to be unloaded or which threads might return at some point to code in the AppDomain to be unloaded. The CLR forces any threads that have the unloading AppDomain on their stack to throw a ThreadAbortException (resuming the thread's execution). This cause the threads to unwind, excuting any finally blocks on their way out so that cleanup code executes. If no code catches the ThreadAbortException, the CLR will swallow the unhandled exception, and the thread dies, but the process si allowed to continue running. This is unusual because for all other unhandled exceptions, the CLR will also kill the process.
        3. The CLR then walks the heap and sets a flag in each proxy objet that referred to an object created by the AppDomain to be unloaded.  These proxy objects now know that the real object they referred to is gone. If any code now calls a method on an invalid proxy object, the method will throw an AppDomainUnloadedException.
        4. The CLR forces a GC to occur, reclaiming the memory used by any objects that were created by the AppDomain to be unloaded. The Finalize methods for these objects are called, giving the objects a chance to clean themselves properly.
        5. The CLR resumes all of the remaining threads. The thread that called AppDomain.Unload will now continue running and Appomain.Unload  is called synchronously.

      
    Please mark the right answer at right time.
    Thanks,
    Sam
    • Marked as answer by SamAgain Tuesday, February 9, 2010 4:22 AM
    Friday, February 5, 2010 6:21 AM
  • I implemented a Designer which rendered all GUI elements in the passed assembly via reflection. This Designer should be used by our customers to customize their GUI's without the power of VS.

    I also used AppDomains in the way you wan't...


    Monday, February 8, 2010 12:28 PM