`
qkgf91qkgf
  • 浏览: 13295 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

DLL和exe里的malloc和free不能混用的问题

阅读更多

DLL和exe里的malloc和free不能混用的问题
2010年12月26日
  今天老玉米提了一个问题问为什么dll里malloc的内存如果在exe里free的话会出错,我分析了一下C库的原代码,得出结论如下:
  刚看了一下malloc和free 的源代码,在这两个函数中都有对全局变量的引用,而malloc和free是C库函数,分别被静态链接到exe和dll里,这样他们引用的全局变量也会有两份各是各的,自然不能混用。
  GlobalAlloc之类的windows API函数应该行。
  茶壶贴了一贴,说dll因为有自已的堆栈所以不能混用,我表示怀疑,继续看源代码,找到支持上面结论的真正原因:
  DLL是否有自已的堆栈我不知道, 但dll和exe里的malloc和free不能混用的真正原因就是我上面说的,有源代码为证, 
  malloc 里真正分配的是这一句,见malloc.c里 
  return HeapAlloc( _crtheap, 0, size ); 
  _crtheap是个全局变量,在_heap_init这个函数里初始化,见heapinit.c: 
  //  Initialize the "big-block" heap first. 
  if ( (_crtheap = HeapCreate( mtflag ? 0 : HEAP_NO_SERIALIZE, BYTES_PER_PAGE, 0 )) == NULL ) 
  return 0; 
  而_heap_init 在wWinMainCRTStartup 这个函数里调用(见crt0.c),同时也会在_DllMainCRTStartup里调用(见dllcrt0.c )。而winmain和dllmain 分别在wWinMainCRTStartup  和DllMainCRTStartup里调用,但都在调用了_heap_init之后(事实上是DllMainCRTStartup调用了_CRT_INIT之后才会调用用户的dllmain,而_CRT_INIT里调用了_heap_init这也就是说至少_crtheap这个变量在dll和exe里会各有一份,这才是dll和exe里不能混用malloc和free的真正原因。
  如果使用LoadLibraryEx装入dll,并指定DONT_RESOLVE_DLL_REFERENCES参数来让系统不调用用户的dllmain,dll和exe的malloc和free仍然不能混用,因为即使指定了DONT_RESOLVE_DLL_REFERENCES参数DllMainCRTStartup里仍会调用_CRT_INIT来初始化自已的_crtheap。
  [补充]
  DLL中的内存分两类,一类是共享内存,一类是进程私有内存
  例如,进程P1和P2同时引用同一个DLL,一般情况下,DLL中声明的变量会在P1和P2的进程空间内产生各自的副本
  也就是说,DLL中的变量,对于各个进程是独立的
  某些情况下,有必要在DLL中产生一块共享内存,多个进程都访问到同一块数据,比如,某些设备驱动程序,需要内部保留一个设备忙/空闲之类的状态标志,这个标志就必须作为共享内存存在,保证只有一份
  对于DLL中分配的内存,我觉得本身没有什么神秘之处,Windows程序之下的内存分配,最终都需要通过OS来完成,老玉米的问题,很可能是象北京色狼说的那样,不是内存本身的问题,是内存管理程序的故障
  因为各种语言的RTL库中的内存管理程序,它本身也需要通过自己的内部数据来管理内存分配的状态
  在DLL中调用的内存管理程序和在EXE中调用的内存管理程序不是同一块,而且它们内部维护内存分配信息的数据也不是同一块,所以造成老玉米的问题
  如果上面的说法成立的话,那么,不要用C的RTL来申请和释放内存,直接通过Windows API来申请和释放内存,比如GlobalAlloc/GlobalFree/LocalAlloc/LocalFree/HeapAl loc/HeapFree等等,应该就不会有问题了
  老玉米快去测试,报告结果
  当然如果dll和exe的编写语言不同的话,更不能混用了,各种语言都会封装winAPI来实现自已的内存管理库函数。
  原文地址: http://bjwf.cndev.org/2004/06/03/559/
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics