【问题标题】:DLL unloading procedureDLL 卸载程序
【发布时间】:2016-04-21 00:52:58
【问题描述】:

我确实解决了手头的直接问题,但现在我需要了解它为什么会解决。 ;-)

所以我还有几个问题。

假设我有一个从 DLL 导出的类。现在每次调用时都应该将这个 DLL 加载到内存中:

MyExportedClass *pb = new MyExportedClass;

它应该留在内存中,只有在我调用时才会被卸载:

delete pb;

这对吗?

如果我理解正确并且上一个问题的答案是肯定的,那么在以下情况下应该会发生什么:

我有一个从 dll (dll1) 导出的接口,我有一个从另一个 dll (dll2) 导出的实现。所以每次我执行:

MyInterface *pInterface = new MyImplementation;

这两个 dll 都应该加载到内存中,并且它们应该保留在内存中,直到我调用:

delete pInterface;

这对吗?

现在,如果这个问题的答案是肯定的 - 我是否有控制/说法,首先卸载哪个库,然后是哪个库?或者卸载总是在调用适当类的析构函数后发生?

现在,是否有一个工具可以检查库是否已卸载以及何时卸载?我可能只使用假的 DllMain() 并检查它的 process_detach 情况,但我的印象始终是:在库导出函数时使用 DllMain,在库导出类时不要使用 DllMain。我从 MSVC 5/6 开始就使用这种方法(遵循一本关于 C++ 的书)。

我错了吗,在这两种情况下我仍然可以使用 DLLMain?

谢谢。

【问题讨论】:

  • 为什么你认为对象的每次实例化/销毁对整个 DLL 都一样?
  • 我对操作系统的理解是,只有在需要内存时(由另一个 DLL、程序等),才会从内存中卸载 DLL。删除对象不会强制卸载 DLL。
  • @deviantfan,不确定你的意思。能详细点吗?
  • @ThomasMatthews,但是当 DLL 被卸载时,我们会有一个悬空指针,对吧?我的意思是对象可以调用函数,但是如果没有 dll,它只会崩溃。那是除非我遗漏了一些东西,并且在这种情况下 dll 将由操作系统自行加载。
  • not sure what you mean 我的意思是你在问题中的第一个Is this correct? 的答案是No。因此,其余的都没有意义了。

标签: c++ dll


【解决方案1】:

DLL 加载可以是自动的(如果在导入表中列出)或手动的(使用LoadLibrary)。一些托管框架(如 .NET)会在其元数据中看到 DLL 导入声明时为您静默调用 LoadLibrary,但 C++ 不是其中之一。 C++ 最接近的是延迟加载,其中调用LoadLibrary 的函数是(默认情况下,您可以替换您自己的)由编译器提供。

另一方面,DLL 卸载始终是手动的。删除对象绝不会隐式卸载 DLL。您必须致电FreeLibrary(或FreeLibraryAndExitThread)。并且您最好不要在该库中定义的对象仍在使用时调用 FreeLibrary

现在,Windows 中的 COM 系统有点复杂,因为它为您管理 DLL 的生命周期。但是 DLL 的生命周期仍然不受对象删除的控制,而是通过调用 DLL 中的 DllCanUnloadNow 函数来控制。通常,您需要维护活动对象的数量才能正确编写该函数。但它仍然需要您手动实现,并且您可以简单地始终返回 false 以永不卸载(这在开发过程中有点痛苦,因为您必须关闭整个应用程序才能尝试新的插件版本等......但实际上释放每次使用 DLL 并成功卸载它的情况很少见)

当然,没有什么会自动卸载导入表中列出的 DLL,它们在进程启动期间加载并且永远不会卸载,无论创建或销毁多少对象实例。

【讨论】:

  • 我必须调用 FreeLibrary{AndExitThread}() 吗?如果我不这样做会怎样?操作系统会解决这个问题吗?请记住,我没有导出调用函数的函数并忘记了库 - 我正在导出一个由指针实例化的 C++ 类。那么,如果我不卸载 dll,会发生什么?操作系统会处理没有人引用 dll 的问题吗? AFAIU,这是一个模块句柄,不会被释放,所以会是资源泄漏吧?
  • @Igor:当进程退出时,它的 DLL 被操作系统释放。除非您导致调用FreeLibrary,否则只要进程存在,DLL 就会一直保留在内存中。您可以认为是资源泄漏,但它只是一次,无论您使用 DLL 中有多少类实例和函数,所以它并不重要。当人们谈论内存泄漏错误时,他们谈论的是每次操作运行时都会发生泄漏并随着时间的推移而累积。
  • 感谢您的解释。
猜你喜欢
  • 1970-01-01
  • 2012-02-19
  • 2016-05-28
  • 1970-01-01
  • 2023-02-06
  • 1970-01-01
  • 1970-01-01
  • 2012-10-19
  • 1970-01-01
相关资源
最近更新 更多