模块连接C/C++运行库的静态版本和动态版本不同的疑问

ding1188 2009-03-07 02:46:56
windows核心编程中提到,模块中存在如下代码
Void EXEFunc(){
PVOID pv = DLLFunc();
free(pv);
}
PVOID DLLFunc(){
return (malloc(100));
}

在连接到C/C++运行库的静态版本时,free调用就会失败。为什么调用 malloc就不会失败呢?
...全文
549 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
countryhuuu 2011-09-03
  • 打赏
  • 举报
回复
今天也看了《Windows核心编程》“DLL和进程的地址空间”这一节,对为什么不同模块只要不是都加载的C/C++ 运行库的DLL版本,就会存在内存管理不一致的问题有疑问,看了大家的专注的讨论又看了遍书,觉得有些理解了。
先说两个模块都加载的静态库吧。编译的时候模块A加载了一份单独的运行库代码,模块B也加载了一份单独的运行库代码。两份代码各自有自己的数据结构管理自己申请过的内存。在模块A中申请的内存,记录在模块A的数据结构中。如在模块B释放此内存,模块B中的运行库在自己的数据结构中无法查到此内存的信息。自然会释放失败。
再说两个模块都加在的DLL版本,由于一个进程中不同模块共享同一份运行库代码,相当于公用同一个全局变量。在模块A和模块B申请和释放内存,是公用同一份管理数据结构。所以可以成功释放。
对于一份是DLL版本一份是静态库版本同样是不同的管理数据结构。所以会失败。
我的理解过于浅显,希望各位指正!
zwb32167 2011-08-28
  • 打赏
  • 举报
回复
DLL若连接的是静态版本,那么DLL的代码里面就会有一份free和malloc的代码,若EXE也使用的是静态版本的C/C++运行库,那么也会有另一份代码。当然你使用DLL代码里申请的内存不能在EXE的free代码中释放。原因是因为有两个不通的堆管理,在EXE中查不到相应申请的内存,自然释放会失败。
zhangjinqing1234 2010-07-07
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 ding1188 的回复:]
引用 8 楼 cs60089 的回复:
exe和dll都静态链接,则各有一个C运行库heap
C运行库利用一个链表来管理动态分配的内存,每malloc一笔,都会在local heap中登记信息修改链表,同样,free也相应会修改链表
跨模块边界传递的由malloc而来的指针地址再另一个模块中是不能被正常识别的,

==================
老外说了一堆,就是这意思,该仁兄言……
[/Quote]
这位仁兄的意思是,在exe和dll模块中,都有free和malloc存在,但是不能用exe模块中的free去释放由dll模块中的malloc分配的内存空间....
ding1188 2009-03-08
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 cs60089 的回复:]
exe和dll都静态链接,则各有一个C运行库heap
C运行库利用一个链表来管理动态分配的内存,每malloc一笔,都会在local heap中登记信息修改链表,同样,free也相应会修改链表
跨模块边界传递的由malloc而来的指针地址再另一个模块中是不能被正常识别的,

==================
老外说了一堆,就是这意思,该仁兄言简意赅,只可惜很少人能够读懂!
[/Quote]
的确没读懂,上面的代码,free和malloc不是在一个模块中吗?
Holly 2009-03-08
  • 打赏
  • 举报
回复
对于此类设计,最好还是避免,应当把这种内存的使用封装起来。
这里我就不重复,有兴趣的参考一下我在另外一帖的回复。
http://topic.csdn.net/u/20090220/12/9b07f419-f1a5-4bd4-8f67-60b8d2609d23.html
很土 2009-03-08
  • 打赏
  • 举报
回复
所谓静态库就是直接把中间代码.obj或.o通过link编译到可执行的二进制编码中,你可以把静态库看作为你自己代码的一部分,所以free和malloc当然是属于同一模块中了。
ding1188 2009-03-08
  • 打赏
  • 举报
回复
看了各位的解释,我还是有个问题:
当模块连接C/C++运行时库的静态版时, free和malloc由连接器把这两个函数的代码复制到模块中(我的理解),那么,free和malloc不是都在一个模块中吗?
菜牛 2009-03-08
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 ding1188 的回复:]
看了各位的解释,我还是有个问题:
当模块连接C/C++运行时库的静态版时, free和malloc由连接器把这两个函数的代码复制到模块中(我的理解),那么,free和malloc不是都在一个模块中吗?
[/Quote]可是你的exe和dll不是一个模块。
cs60089 2009-03-08
  • 打赏
  • 举报
回复
每个crt copy都有自己的堆
cs60089 2009-03-07
  • 打赏
  • 举报
回复
exe和dll都静态链接,则各有一个C运行库heap
C运行库利用一个链表来管理动态分配的内存,每malloc一笔,都会在local heap中登记信息修改链表,同样,free也相应会修改链表
跨模块边界传递的由malloc而来的指针地址再另一个模块中是不能被正常识别的,

==================
老外说了一堆,就是这意思,该仁兄言简意赅,只可惜很少人能够读懂!
cs60089 2009-03-07
  • 打赏
  • 举报
回复
这是我的原贴:

fifth Edition
in Chapter 19, there is one note:

Note: It is important to realize that a single address space consists of one executable module and several DLL modules. Some of these modules can link to a static version of the C/ C++ run-time library, some of these modules might link to a DLL version of the C/C++ run-time library, and some of these modules (if not written in C/C++) might not require the C/ C++ run-time library at all. Many developers make a common mistake because they forget that several C/C++ run-time libraries can be present in a single address space. Examine the following code:

VOID EXEFunc() {
PVOID pv = DLLFunc();
// Access the storage pointed to by pv...
// Assumes that pv is in EXE's C/C++ run-time heap
free(pv);
}

PVOID DLLFunc() {
// Allocate block from DLL's C/C++ run-time heap
return(malloc(100));
}

So, what do you think? Does the preceding code work correctly? Is the block allocated by the DLL's function freed by the EXE's function? The answer is: maybe. The code shown does not give you enough information. If both the EXE and the DLL link to the DLL C/C++ run-time library, the code works just fine. However, if one or both of the modules link to the static C/C++ run-time library, the call to free fails. I have seen developers write code similar to this too many times, and it has burned them all.


===========================================================================

At first one thing the starup() function do is to initialize a heap used by malloc and free and low-level IO manipulation use in CRT, so when there is two copies CRT liberary in one process adress and there will be two heaps for two groups of malloc and free, and that one block memory grabed by malloc can only be freed by the very free() function in the same copy.

but what free() is?

in fact free()'s source code is like this:

void free(void *ptr)
{
struct mem_control_block *free;
free = ptr - sizeof(struct mem_control_block);
free->is_available = 1;
return;
}


every malloc()function return pointer to a block,however there are some bytes ahead the block conserved for system information, and this information is stored in a struct mem_control_block, so indeed the pointer malloc()function returned points to the byte after the mem_control_block.

struct mem_control_block {
int is_available; //a flag that specify whether this block can be used by any other application
int size; //the size of the block
};



finnally, it seems no error in these code:

VOID EXEFunc() {
PVOID pv = DLLFunc();
// Access the storage pointed to by pv...
// Assumes that pv is in EXE's C/C++ run-time heap
free(pv);
}

PVOID DLLFunc() {
// Allocate block from DLL's C/C++ run-time heap
return(malloc(100));
}

if the system doesn't allow a free() to free a block in heap of another copy of CRT, then how the system is able to forbid?????

Thanks for your help.
I'm struggle reading win via c/c++
cs60089 2009-03-07
  • 打赏
  • 举报
回复
昨天与一老外也在讨论这个问题,这是他的答复,不一定正确,但是有他的经验:

And to answer your question about DLL and local heap. This time I mean the heap

Win16 dll could and usually had a local heap in local sense and that one was mapped into the global memory space and then dll was used system wide. Memory management simply required to create and destroy object from dll because memory management was such that exe did not know about the position of a dll memory in the global space. It was just using it. The memory management was never constructed to support sharing a heap unless specified that memory block is such.

Win32 is mapping each dll into one and the same process space. So we should not have a problem with asking a memory from dll giving it to dll deleting new-ing, whatever. Right? Alas, we are sure that this is true only if we use system allocator functions properly. They do everything as it should be done and we have no problem with pointers from and to dll's as long as the same allocators are used which might not be the case if the system libraries are different. The problem is that some dll's have kept "old" or somehow adjusted memory managers that know nothing about Win32 sharing capabilities. They behave as if we are still dealing with Win16.
I would not be surprised at all, and I have met them, such compilers and C implementations of free, maloc, new and delete even today.
And the problem is of course if different dll's use different allocators.

Even under Win32, a dll still has its own local heap, it is just accessible from the main process. If you would do this: load dll, create some object on its heap, save the pointer in exe, unload dll, you would not be able to delete that object any longer, the pointer you have is invalid: no dll - no local heap.

Still this behavior asks for attention. You may have a static member pointer in a dll. You create an object and save the pointer into the static member variable. You go to another dll and ask for the static member pointer and nothing... though the space is shared and every heap accessible, the space of static members can be separated.

And this all picky details together create very difficult situation during development. If different teams have to use the same classes over several dll's and the application has a heavy pointer usage - watch out !

All in all you have to know what memory manager you use to be certain.
liuzxchina 2009-03-07
  • 打赏
  • 举报
回复
一般在dll中分配的内存,都需要通过dll释放。
很土 2009-03-07
  • 打赏
  • 举报
回复
堆的范围出界,无权直接释放其他MODULE的动态分配指针,可以由其他MODULE提供释放函数即可。
wocow3 2009-03-07
  • 打赏
  • 举报
回复
exe和dll都静态链接,则各有一个C运行库heap
C运行库利用一个链表来管理动态分配的内存,每malloc一笔,都会在local heap中登记信息修改链表,同样,free也相应会修改链表
跨模块边界传递的由malloc而来的指针地址再另一个模块中是不能被正常识别的,
菜牛 2009-03-07
  • 打赏
  • 举报
回复
malloc只是申请内存,自然不会失败;free的时候由于静态库和动态库(这时候DllFunc是从dll导出的函数吧)行为的不同会导致出错。你把malloc和free放在一个模块就没问题。

这个例子应该是告诉我们,不要在模块之间进行内存的申请和释放;如果有必要,应该使用API的内存管理函数,比如GlobalAlloc、GlobalFree等。
对于OLE、COM等需要跨进程的内存管理,应该使用OLE专用的IMalloc等方式。
lhsxsh 2009-03-07
  • 打赏
  • 举报
回复
up

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧