一个DLL应该释放堆内存只有当DLL动态卸载?

问题描述 投票:0回答:2

问目的:在MS docs of DllMain现实检查。

这是“共同”知识你不应该做DllMain中太多了,有明确的东西,你必须永远不会做,有些best practises

现在我绊倒在文档中一个新的宝石,那没有什么意义,我:(EMPH矿)

当处理DLL_PROCESS_DETACH,一个DLL应释放的资源,例如仅当DLL被动态地卸载(在lpReserved参数是NULL)堆存储器。如果进程终止(该lpvReserved参数为非NULL),在这个过程中的所有线程除了当前线程要么已经退出已经或已被明确为ExitProcess函数的调用,这可能会留下一些处理资源,如堆终止处于不一致的状态。在这种情况下,它是不是安全的DLL清理资源。相反,DLL应该允许操作系统回收内存。

由于全球C ++对象的DllMain /分离期间清理,这将意味着全球C ++对象决不能释放任何动态内存,因为堆可能是不一致的状态。 /当DLL被“挂静态”的可执行文件。 /当然不是我所看到的在那里 - 全球C ++对象(IFF有)的不同(我们和第三方)库分配和析构函数解除分配就好了。 (除非其他订购的错误,o.c.)

那么,这个警告针对哪些具体的技术问题?

由于该段提到线程终止,莫不是当一些线程不清理正确,堆腐败问题?

winapi visual-c++ dll entry-point dllmain
2个回答
1
投票

一般qazxsw POI API执行以下操作:

  • 进入Loader锁定关键部分
  • 经由ExitProcessGetProcessHeap()锁定主进程堆(由HeapLock返回)(确定,当然通过(GetProcessHeap()))(这是为避免死锁非常重要的一步)
  • 然后终止所有线程的过程中,除了电流(通过调用RtlLockHeap
  • 然后调用NtTerminateProcess(0, 0) - 内通过加载模块列表此API装载机的步行路程,与LdrShutdownProcess非空发送DLL_PROCESS_DETACH
  • 最后调用lpvReserved结束处理。

这里的问题是,在任意位置终止线程。例如,线程可以分配或从任何堆的可用内存,并堆内部临界区,当它终止。其结果是,如果NtTerminateProcess(NtCurrentProcess(), ExitCode )期间代码试图从同一个堆释放块,它试图进入这个堆的关键部分(如课程的堆实现使用)时死锁。

请注意,这不会影响主进程堆,因为我们称之为DLL_PROCESS_DETACH它之前终止所有线程(除了电流)。这样做的目的:我们在等待这个调用,直到从进程堆关键部分的所有其他线程退出后,我们获得了关键的部分,没有其他线程可以进入它 - 因为主进程堆被锁定。

所以,当我们终止锁定主堆后,线程 - 我们可以肯定的是被杀死没有其他线程内部不一致的状况的主要堆临界区或堆结构。由于HeapLock通话。但是,这仅与主进程堆。在这个过程中的任何其他堆未锁定。因此,这些可以RtlLockHeap过程中可能处于不一致的状态,或者可以通过已经终止线程以独占方式收购。

所以 - 使用DLL_PROCESS_DETACH HeapFree或者说GetProcessHeap是安全的(但是没有记录)在这里。

使用LocalFree任何其他堆如果HeapFree的进程终止时调用是不安全的。

此外,如果你通过使用多个线程另一个自定义数据结构 - 它可以是不一致的状态,因为另一个线程(可使用)在任意点终止。

因此,这记警告说,当lpvReserved参数为非NULL(什么是平均DllMain是因为进程终止时的称呼),你需要在清理的资源特别小心。反正所有内部内存分配将是操作系统免费的,当进程死亡。


0
投票

作为附录RbMm的出色答卷,我会从DllMain,做一个更好的工作添加报价 - 比DllMain的文档做的 - 在解释,为什么堆操作(或任何操作,真的)可能会受到影响:

如果在该过程中终止的线程之一持有锁,并在加载的DLL试图获取同一个锁中的一个的DLL分离代码,然后调用ExitProcess死锁结果。与此相反,如果一个进程通过调用ExitProcess,该工艺被附接到不被通知该过程终止的DLL终止。因此,如果你不知道在你的进程中的所有线程的状态,最好是打电话TerminateProcessTerminateProcess。需要注意的是从应用程序结果的主要功能,在呼叫返回ExitProcess

所以,这一切都归结为:IFF你的应用程序有可能持有的任何锁“失控”的线程,(CRT)堆锁是一个突出的例子,你必须关闭过程中一个很大的问题,当你需要访问相同的结构(如堆),你的“失控”线程使用。

这只是表明你应该关闭在一个可控制的方式所有的线程。

© www.soinside.com 2019 - 2024. All rights reserved.