Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nasty memory leak when loading code in AppDomain

Tags:

c#

appdomain

I have an unusual requirement for some code I am working on. I'm using an unreliable 3rd party library to do some barcode scanning (it stops working after running too many times). To get around this problem I decided to do the work in a separate AppDomain and then to unload the AppDomain when I am finished. This is a simplistic, but accurate, picture of what I am doing:

string domainID = Guid.NewGuid().ToString();
AppDomainSetup setup = new AppDomainSetup();
AppDomain domain = AppDomain.CreateDomain(domainID, null, setup);

string result = null;
try
{
    domain.SetData("stream", stream);
    domain.DoCallBack(ScanningContext.DoWork);

    result = domain.GetData("result") as string;
}
finally
{
    AppDomain.Unload(domain);
}

return result;

public static void DoWork()
{
    Stream s = AppDomain.CurrentDomain.GetData("stream") as Stream;
    ObjectHandle handle = AppDomain.CurrentDomain.CreateInstance("Scanning",
        "Scanner");

    Scanning.Scanner scanner = (Scanning.Scanner)handle.Unwrap();
    Scanning.Result[] results = scanner.Scan(s);

    AppDomain.CurrentDomain.SetData("result", results[0].Text);
}

"Scanner" is a wrapper class around the library I'm using. It sits in the "Scanning" assembly; a separate project just for this purpose.

ScanningContext.DoWork is a static method that sits in my service's assembly.

My problem with this method is that there is a memory leak some where. Memory keeps growing and growing (when this code is called, of course) until OutOfMemoryExceptions are thrown.

I can't find the leak any where. All of my streams are being disposed. All of my byte arrays are being nulled. I'm clearing lists, everything that has worked for me in the past. I'm about 90% confident that the leak is related to this AppDomain stuff. This is my first time using it so I'm probably doing something wrong.

I'm open to another approach besides AppDomains. I do require the ability to return results from the "Scanner" class, so spawning a process is not an option.

like image 490
Matthew Avatar asked Nov 04 '22 06:11

Matthew


1 Answers

The AppDomain.Unload method starts a separate thread to unload the domain, which may fail for various reasons (threads executing unmanaged code is a problem). Here is a sample code that checks if the app domain is unloaded (taken from msdn docs):

 try
 {
 Console.WriteLine();
 // Note that the following statement creates an exception because the domain no longer exists.
 Console.WriteLine("child domain: " + domain.FriendlyName);
 } 
 catch (AppDomainUnloadedException e)
 {
 Console.WriteLine("The appdomain MyDomain does not exist.");
 }
like image 79
muratgu Avatar answered Nov 09 '22 14:11

muratgu