Windows 下主程序与动态库(*.dll)释放对方分配的内存操作要点
2014-11-13 11:06
471 查看
同样的代码程序:
主程序中释放了一块在 动态库(*.dll)或共享库(*.so) 中分配的内存,
Windows 将会出现程序崩溃,而 Linux 则正常运行。
在 linux 下,每个进程只有一个 heap ,
在任何一个共享库模块 *.so 中通过 new 或者 malloc 来分配内存的时候都是从这个唯一的 heap 中分配的,
那么自然你在其它什么地方都可以释放。
但是 windows 下面确不是如此:
1. windows 允许一个进程中有多个 heap ,那么这样就需要指明一块内存要在哪个 heap 上分配,
win32 的 HeapAlloc 函数就是这样设计的,
给出一个 heap 的句柄、一个可选的分配操作标志、一个字节块大小,然后返回一个指针。
每个进程都至少有一个主 heap ,它的句柄可以通过 GetProcessHeap 来获得,
其它的堆句柄可以通过 GetProcessHeaps 取到。
同样,内存释放的时候通过 HeapFree 来完成,还是需要指定一个堆句柄。
2. 这样的设计显然是比较灵活的,
但是问题在于这样的话,每次分配内存的时候就必须要显式的指定一个 heap 句柄,
对于 crt 中的 new/malloc ,显然需要特殊处理。
那么如何处理就取决于 crt 的实现了。
VC++ 的 crt 是创建了一个单独的 heap,叫做 __crtheap ,它对于用户是看不见的,
但是在 new/malloc 的实现中,都是用 HeapAlloc 在这个 __crtheap 堆上分配的,
也就是说 malloc(size) 基本上可以认为等同于 HeapAlloc(__crtheap, size)
(当然实际上 crt 内部还要维护一些内存管理的数据结构,
所以并不是每次 malloc 都必然会触发 HeapAlloc ),
这样 new/malloc 就和 windows 的 heap 机制吻合了。
(这里说的是 VC 的 crt 实现,我不知道其它 crt 实现是否如此)
3. 如果一个进程需要动态库支持,系统在加载 dll 的时候,在 dll 的启动代码 _DllMainCRTStartup 中,
会创建这个 __crtheap ,所以理论上有多少个 dll,就有多少个 __crtheap 。
最后主进程的 mainCRTStartup 中还会创建一个为主进程服务的 __crtheap 。
(由于顺序总是先加载 dll ,然后才启动 main 进程,
所以你可以看到各个 dll 的 __crtheap 地址比较小,
而主进程的 __crtheap 地址比较大,当然排在最前面的堆是每个进程的主 heap 。)
4. 从上面的分析中可以看出,对于 crt 来说,由于每个 dll 都有自己的 heap ,
所以每个 dll 通过 new/malloc 分配的内存都是在自己 dll 内部的那个 heap 上用 HeapAlloc 来分配的,
而如果你想在其它模块中释放,那么在释放的时候 HeapFree 就会失败了,
因为各个模块的 __crtheap 是不一样的。
事情基本清楚了,在 windows 下一个进程存在着多个 heap ,
除了一个主 heap 外,还有很多的 __crtheap ,用来处理通过 C/C++ 的运行库进行的内存操作。
所以使用 new/malloc 来分配的内存实际上都是局部的,可以在多个 dll 中共享,
但是却必须是谁申请谁释放。
这个是 Windows 下的一个规则。以前知道这个规则,但是不知道为什么,现在算是比较明白了。
如果在 dll 内部使用 HeapAlloc(GetProcessHeap(), 0, 字节块大小 ) 来分配的内存,
是可以在 dll 以外释放的,
因为这时内存分配在全局的主 heap 上,而不是分配在 dll 自己的 __crtheap 上。
转自 http://blog.sina.com.cn/s/blog_4c451e0e0100u9gu.html
主程序中释放了一块在 动态库(*.dll)或共享库(*.so) 中分配的内存,
Windows 将会出现程序崩溃,而 Linux 则正常运行。
在 linux 下,每个进程只有一个 heap ,
在任何一个共享库模块 *.so 中通过 new 或者 malloc 来分配内存的时候都是从这个唯一的 heap 中分配的,
那么自然你在其它什么地方都可以释放。
但是 windows 下面确不是如此:
1. windows 允许一个进程中有多个 heap ,那么这样就需要指明一块内存要在哪个 heap 上分配,
win32 的 HeapAlloc 函数就是这样设计的,
给出一个 heap 的句柄、一个可选的分配操作标志、一个字节块大小,然后返回一个指针。
每个进程都至少有一个主 heap ,它的句柄可以通过 GetProcessHeap 来获得,
其它的堆句柄可以通过 GetProcessHeaps 取到。
同样,内存释放的时候通过 HeapFree 来完成,还是需要指定一个堆句柄。
2. 这样的设计显然是比较灵活的,
但是问题在于这样的话,每次分配内存的时候就必须要显式的指定一个 heap 句柄,
对于 crt 中的 new/malloc ,显然需要特殊处理。
那么如何处理就取决于 crt 的实现了。
VC++ 的 crt 是创建了一个单独的 heap,叫做 __crtheap ,它对于用户是看不见的,
但是在 new/malloc 的实现中,都是用 HeapAlloc 在这个 __crtheap 堆上分配的,
也就是说 malloc(size) 基本上可以认为等同于 HeapAlloc(__crtheap, size)
(当然实际上 crt 内部还要维护一些内存管理的数据结构,
所以并不是每次 malloc 都必然会触发 HeapAlloc ),
这样 new/malloc 就和 windows 的 heap 机制吻合了。
(这里说的是 VC 的 crt 实现,我不知道其它 crt 实现是否如此)
3. 如果一个进程需要动态库支持,系统在加载 dll 的时候,在 dll 的启动代码 _DllMainCRTStartup 中,
会创建这个 __crtheap ,所以理论上有多少个 dll,就有多少个 __crtheap 。
最后主进程的 mainCRTStartup 中还会创建一个为主进程服务的 __crtheap 。
(由于顺序总是先加载 dll ,然后才启动 main 进程,
所以你可以看到各个 dll 的 __crtheap 地址比较小,
而主进程的 __crtheap 地址比较大,当然排在最前面的堆是每个进程的主 heap 。)
4. 从上面的分析中可以看出,对于 crt 来说,由于每个 dll 都有自己的 heap ,
所以每个 dll 通过 new/malloc 分配的内存都是在自己 dll 内部的那个 heap 上用 HeapAlloc 来分配的,
而如果你想在其它模块中释放,那么在释放的时候 HeapFree 就会失败了,
因为各个模块的 __crtheap 是不一样的。
事情基本清楚了,在 windows 下一个进程存在着多个 heap ,
除了一个主 heap 外,还有很多的 __crtheap ,用来处理通过 C/C++ 的运行库进行的内存操作。
所以使用 new/malloc 来分配的内存实际上都是局部的,可以在多个 dll 中共享,
但是却必须是谁申请谁释放。
这个是 Windows 下的一个规则。以前知道这个规则,但是不知道为什么,现在算是比较明白了。
如果在 dll 内部使用 HeapAlloc(GetProcessHeap(), 0, 字节块大小 ) 来分配的内存,
是可以在 dll 以外释放的,
因为这时内存分配在全局的主 heap 上,而不是分配在 dll 自己的 __crtheap 上。
转自 http://blog.sina.com.cn/s/blog_4c451e0e0100u9gu.html
相关文章推荐
- Windows 下主程序与动态库(*.dll)释放对方分配的内存操作要点
- .NET Framework-垃圾回收器实现内存的分配、释放,文件的操作和IO流
- DLL分配的内存如何在EXE里面释放
- DLL中用malloc分配了一块内存,但是在exe程序中释放引发的错误:其原因可能是堆被损坏,这也说明 **.exe 中或它所加载的任何 DLL 中有 bug。
- DLL分配的内存如何在EXE里面释放
- 浅析C++内存分配与释放操作过程——三种方式可以分配内存new operator, operator new,placement new
- [Delphi]内存分配和释放 内存操作函数(4): 清空与填充内存
- DLL中内存的分配释放
- Windows编程 在一个模块中分配的内存在另外一个模块释放?
- 浅析C++内存分配与释放操作过程
- 用vs2008写了一个动态库,其中有申请内存,用vc6.0写了一个exe调用动态库,并释放dll申请的内存:dbgheap.c Line:1011
- 一种在接口中跨dll分配释放内存的方法
- EXE中释放DLL中分配的内存
- Windows编程 在一个模块中分配的内存在另外一个模块释放?
- Windows驱动开发小练习-内存分配与链表操作
- DLL中用malloc分配了一块内存,但是在exe程序中释放引发的错误:其原因可能是堆被损坏,这也说明 **.exe 中或它所加载的任何 DLL 中有 bug。
- DLL分配的内存如何在EXE里面释放
- 跨DLL的内存分配释放问题 Heap corruption
- Windows编程 在一个模块中分配的内存在另外一个模块释放?
- Windows驱动开发小练习-内存分配与链表操作