C++ DLL不会与AppDomain一起卸载

use*_*875 12 c# appdomain

我有一个使用单独的C++ DLL的C#插件.对该DLL的唯一引用来自插件本身.父应用程序将所有插件加载到自己的AppDomain中,并在卸载插件时卸载此AppDomain.

我已经检查过,当我卸载插件时,我肯定会看到应用程序的内存丢失.我还能够删除所有已加载的托管程序集.问题是,当我尝试删除本机DLL时,我只是不断访问拒绝,直到我关闭整个应用程序.

我已经看了一段时间,但我仍然无法弄清楚为什么这个DLL留在内存中.

Han*_*ant 20

AppDomains是纯托管代码构造.本机代码中不存在类似内容,Windows也不了解它.因此,加载的本机DLL的范围就是进程.从技术上讲,pinvoke marshaller可以引用计数DLL并准确跟踪哪个AppDomain触发了DLL的加载.然而,它无法判断是否正在运行使用该DLL的本机代码.可以通过另一个 AppDomain中的代码调用启动的本机代码,可能通过封送的委托间接调用.

如果AppDomain管理器卸载以这种方式使用的DLL,那将是一个令人讨厌且无法诊断AccessViolation的灾难.特别讨厌,因为它可以在AppDomain卸载后触发很长时间.

所以marshaller没有实现那种计数,DLL保持加载状态.只有您可以保证不会发生这种情况,您可以控制DLL中运行的代码以及它如何启动.您可以强制DLL卸载但它需要一个hack.Pinvoke LoadLibrary()自己来获​​取DLL的句柄.并且两次将FreeLibrary()旋转,以强行卸载它.Windows和CLR都看不到你在作弊.您必须确保在此之后无法使用DLL.


Yah*_*hia 5

AFAIK(引擎盖下)本机DLL需要通过Win32 API加载LoadLibrary...它将它们直接加载到进程内存中 - 如果.NET应用程序不是特定于AppDomain... ... LoadLibrary一无所知AppDomain(这是纯粹是特定于.NET的)...因此卸载AppDomain不一定卸载本机DLL ...

关于这种情况的有趣讨论:

如果您可以更改相应插件的实现,那么您将实现"晚期本机绑定",这将解决您看到的问题: