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

时间:2012-04-04 15:55:51

标签: c# appdomain

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

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

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

2 个答案:

答案 0 :(得分:20)

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

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

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

答案 1 :(得分:5)

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

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

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