Неприятная утечка памяти при загрузке кода в AppDomain - PullRequest
5 голосов
/ 07 февраля 2012

У меня необычное требование для кода, над которым я работаю. Я использую ненадежную стороннюю библиотеку для сканирования штрих-кода (она перестает работать после запуска слишком много раз). Чтобы обойти эту проблему, я решил сделать работу в отдельном домене приложений, а затем выгрузить домен приложений после завершения. Это упрощенная, но точная картина того, что я делаю:

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" - это класс-оболочка для библиотеки, которую я использую. Он сидит в сборке «Сканирование»; отдельный проект как раз для этой цели.

ScanningContext.DoWork - это статический метод, который находится в сборке моего сервиса.

Моя проблема с этим методом в том, что где-то произошла утечка памяти. Память продолжает расти и расти (когда этот код вызывается, конечно), пока не будут выброшены исключения OutOfMemory.

Я не могу найти утечку где-либо. Все мои потоки утилизируются. Все мои байтовые массивы обнуляются. Я очищаю списки, все, что работало для меня в прошлом. Я примерно на 90% уверен, что утечка связана с этим материалом AppDomain. Я использую его впервые, поэтому, вероятно, я делаю что-то не так.

Я открыт для другого подхода, кроме доменов приложений. Мне требуется возможность возвращать результаты из класса «Сканер», поэтому порождение процесса не вариант.

1 Ответ

2 голосов
/ 09 февраля 2012

Метод AppDomain.Unload запускает отдельный поток для выгрузки домена, который может не работать по разным причинам (проблемы с выполнением неуправляемого кода потоками).Вот пример кода, который проверяет, выгружен ли домен приложения (взят из документации MSDN):

 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.");
 }
...