none
AppDomain.CreateInstance* loads the target assembly into default AppDomain RRS feed

  • Question

  • Hello,

    I'm using a .NET assembly written in C++.NET which does leak memory. (if you are curious: the assembly is tessnet2, which is a managed library from the tesseract OCR engine)
    So my idea was to load this assembly into a seperate AppDomain and then unload the AppDomain after I'm done processing it. But no matter how hard I try, the Assembly gets also always loaded into my default AppDomain, which stays there forever and leaks memory after every method call! This is driving me crazy and I hope someone can help me out.

    Here is a demo application I put together. It consits of 3 class libraries and one main application:



    Interface.dll, a shared library with an interface for my main application and my loader class:
    namespace Interfaces 
        public interface IOCR 
        { 
            void DoOCR(); 
        } 
     



    This is my loader class to load the assembly into the seperate AppDomain
    using Interfaces; 
     
    namespace Tessnet.Loader 
        public class TessnetLoader : MarshalByRefObject, IOCR 
        { 

     
            public void DoOCR() 
            { 
                Assembly _assembly = Assembly.LoadFrom(Environment.CurrentDirectory + "\\Tessnet.dll"); 
                Type _type = _assembly.GetType("Tessnet.Tessnet2"); 
                MethodInfo _method = _type.GetMethod("DoOCR"); 
     
                _method.Invoke(Activator.CreateInstance(_type), null); 
                 
            } 
        } 
     



    This is the actual tessnet.dll which has a reference to the C++.NET assembly which does the actual OCR stuff. In this example DoOCR() does nothing except to create an instance of tessnet2, initialize it and dispose it.
    using tessnet2; 
     
    namespace Tessnet 
        public class Tessnet2 
        { 
            public void DoOCR() 
            { 
                tessnet2.Tesseract ocr = new tessnet2.Tesseract(); 
                ocr.Init("eng"false); 
                ocr.Dispose(); 
            } 
        } 



    And this is the main console Application to demonstrate the problem:
    using Interfaces; 
    using System.Reflection; 
     
    namespace AppDomainTessnet 
        class Program 
        { 
            static IOCR ocr; 
     
            static void Main(string[] args) 
            { 
                PrintAssemblies(); 
     
                AppDomain _appDomain = AppDomain.CreateDomain("TestDomain"); 
                ocr = (IOCR)_appDomain.CreateInstanceFromAndUnwrap( Environment.CurrentDirectory + "\\TessnetLoader.dll""Tessnet.Loader.TessnetLoader"); 
                ocr.DoOCR(); 
                AppDomain.Unload(_appDomain); 
     
                PrintAssemblies(); 
                Console.ReadLine(); 
            } 
     
     
            static void PrintAssemblies() 
            { 
                Console.WriteLine("#####################################################"); 
                foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) 
                { 
                    Console.WriteLine(asm.FullName); 
                } 
                Console.WriteLine("#####################################################"); 
            } 
        } 





    And this is the output of both PrintAssemblies() calls, before loading the assembly and then unloading it through AppDomain.Unload():



    #####################################################
    mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
    AppDomainTessnet, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Interfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    #####################################################



    After AppDomain.Unload():

    #####################################################
    mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
    AppDomainTessnet, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    Interfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
    msvcm80, Version=8.0.50727.3053, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3
    a
    tessnet2, Version=2.0.3.6, Culture=neutral, PublicKeyToken=null
    #####################################################



    As you can see, the msvcm80 and tessnet2 assemblies get loaded into my default AppDomain. Please someone give me a hint what I'm doing wrong. This problem is driving me completely crazy! I'm searching since 2 days through the web, trying every possible AppDomain examples I could find but none of the work for me. THe assemblies always get loaded into default AppDomain.



    Thanks in advance for any insightful hints!



    • Edited by PetrFoxx Friday, March 6, 2009 12:45 PM typo
    Friday, March 6, 2009 12:44 PM

Answers

  • > leaks memory after every method call

    If this is an unmanaged memory leak, then unloading AppDomains will not help since the CLR cannot see memory allocated using unmanaged means.  You might already know this, but just in case.

    • Marked as answer by PetrFoxx Sunday, March 8, 2009 1:01 PM
    Friday, March 6, 2009 11:28 PM

All replies

  • > leaks memory after every method call

    If this is an unmanaged memory leak, then unloading AppDomains will not help since the CLR cannot see memory allocated using unmanaged means.  You might already know this, but just in case.

    • Marked as answer by PetrFoxx Sunday, March 8, 2009 1:01 PM
    Friday, March 6, 2009 11:28 PM
  • To be honest, I didn't know that! I'm still fairly new to the .NET world. Thanks for clearing things up.
    Sunday, March 8, 2009 1:01 PM
  • I "solved" this problem for tesseract/tessnet2 by referencing it in separate executable, and then starting that executable in its own process from my main application.  It's substantially slower than making the API calls directly from the main app, but it does let you get around the memory leak issue.
    Monday, May 3, 2010 3:50 PM
  • Hi Adam,

    Could you explain it more.

    How can I call a method in the seperate process? I've tried to load the executable ( OCR ) from the main application, but i don't have any access to my method DoOCR()

     

    Wednesday, September 15, 2010 9:32 AM