2012-04-04 2 views
10

У меня есть плагин C#, который использует отдельную DLL на C++. Единственная ссылка на эту DLL - из самого модуля. Родительское приложение загружает все плагины в свой собственный AppDomain и выгружает этот AppDomain, когда плагин выгружается.C++ DLL не выгружается с AppDomain

Я проверил, и я определенно вижу падение памяти приложения при разгрузке плагина. Я также могу удалить все загруженные управляемые сборки. Проблема в том, что когда я пытаюсь удалить родную DLL, я просто продолжаю получать Access Denied, пока не закрою все приложение.

Я смотрел на это некоторое время, но я до сих пор не могу понять, почему именно эта DLL остается в памяти.

ответ

18

AppDomains - это чистая управляемая конструкция кода. В собственном коде ничего подобного не существует, и Windows не знает об этом. Таким образом, область для загруженной собственной DLL - это процесс. Технически, маркерщик pinvoke мог ссылаться на подсчет DLL и отслеживать, какой именно AppDomain запускал загрузку DLL. Однако он не может определить, работает ли какой-либо собственный код, который использует эту DLL. Исходный код, который может быть запущен вызовом, сделанным из кода в , еще AppDomain, возможно, косвенно через маршалированного делегата.

Очевидно, что катастрофа удаляется, если менеджер AppDomain выгружает DLL, которая используется таким образом, это неприятно и невозможно диагностировать AccessViolation. Особенно неприятно, так как это может вызвать долгое время после того, как AppDomain разгрузится.

Таким образом, маршаллер не выполняет такой подсчет, DLL остается загруженным. Только вы можете предоставить гарантию, что этого не может быть, у вас есть определенный контроль над тем, какой код работает в DLL и как он запускается. You может заставлять DLL выгружать, но требует взлома. Pinvoke LoadLibrary(), чтобы получить доступ к DLL. И pinvoke FreeLibrary() дважды, чтобы заставить его выгрузить принудительно. Ни Windows, ни CLR не могут видеть, что вы обманываете. Вы должны убедиться, что после этого DLL не может быть использована.

+3

+1 nice hack :-) – Yahia

+0

Эй, просто хотел сказать спасибо за очень четкий ответ! – user472875

5

AFAIK (под капотом) нативные библиотеки DLL должны быть загружены с помощью Win32 API LoadLibrary ... который загружает их непосредственно в памяти процесса - в случае .NET приложения, которое не относится к конкретному AppDomain ... LoadLibrary абсолютно ничего не знает о AppDomain (который является чисто .NET-специфическим) ... Таким образом, разгрузкой AppDomain не обязательно выгружать родную библиотеку DLL ...

Интересных дискуссий относительно этой ситуации:

Если вы можете изменить реализацию соответствующего плагина, то вы бы реализовать «позднюю выходца связывания», который позволит решить проблему, которую вы видите:

Смежные вопросы