C++ DLL не выгружается с помощью AppDomain


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

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

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

2 11

2 ответа:

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

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

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

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

Интересные дискуссии по этому поводу ситуация:

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