在Dll中申请了内存,现在想在Exe模块中释放这部分内存.但不成功.

在Dll中申请了内存,现在想在Exe模块中释放这部分内存.但不成功.楼主ecore2()2001-01-12 09:49:00 在 VC/MFC / 基础类 提问
谢谢
问题点数:0、回复次数:17
Top
 

1 楼bugn(unknown& whoami)回复于 2001-01-12 10:17:00 得分 0 如果用了CRT的内存分配(new,delete,malloc,free,...),你的dll和exe是静态或动态连接CRT的时候必须一致。msvcrt.dll用了单独的一个heap的,跟你的静态连接crt时用的heap不相同。  
  project   settings->c/c++->code   generation->use   runtime   library->dll和exe选择要一致
Top

2 楼kinghan(懒散的牛)回复于 2001-01-12 10:19:00 得分 0 内存指针还有效吗?
Top

3 楼Smile_Tiger(笑面虎)回复于 2001-01-12 10:21:00 得分 0 如果在dll中是用GlobalAlloc()分配的内存,在exe中是可以釋放的
Top

4 楼ab(ab)回复于 2001-01-12 10:27:00 得分 0 用   new   和   delete   的内存不能跨模块。你可以:  
  从   DLL   导出一个释放内存的函数,在   EXE   里面凡是从   DLL   分配的内存都用它释放。
Top

5 楼bugn(unknown& whoami)回复于 2001-01-12 10:29:00 得分 0 有效的。crt是在heap中分配的,heap在同一个进程内是有效的。GlobalAlloc是在每个进程的默认heap种分配的,一个进程可以使用多个heap。  
   
  crt使用单独的heap,刚才我前面说的还有点问题,就是如果是静态连接CRT,那么CRT在每个模块都用一个单独的heap;如果动态连接CRT(msvcrt.dll),那么所有用msvcrt.dll的模块就共享一个heap。
Top

6 楼Robert2001(Robert2001)回复于 2001-01-12 11:25:00 得分 0 系统为每一个进程维护一个4G的虚拟内存,你这EXE里的指针所指向的内存根本就不是DLL中的!  
  最好在你的DLLMAIN   里去释放它。   如果想要实现数据共享的话   ,用内存CreatFileMapping  
    或者用   #pragma     data_("Shared")  
                  volatile   You_value  
                  #pragma     data_seg()  
           
                  #pragma   comment   (Linker,"/Sectioin:Shared,RWS")  
 
Top

7 楼ciba(风子)回复于 2001-01-12 11:34:00 得分 0 正规的话应该在dll的dllMain函数里来处理,case   DLL_PROCESS_ATTACH:  
  case   DLL_PROCESS_DETACH:两种情况分别处理了dll创建和摧毁,可以在此时分配内存和释放内存。在Exe中释放dll的内存,如果该dll还有用,释放掉它的内存合理吗?  
 
Top

8 楼kylewu(水皮)回复于 2001-01-12 12:09:00 得分 0 这个话题以前已经讨论过了,总之这种方法就是不规范,是造成非法操作的诱因之一,最好不要用。   :)  
   
  在dll中,new和delete的管理数据和exe是分开的,因此在dll中new的东西到了exe中,虽然指针不是非法,不过在delete的时候就会出错,如果在debug版会出assert   fail,如果是release版,可能不会报错,不过很可能造成memory   leak或者access   violation。
Top

9 楼newx(Royale with Cheese)回复于 2001-01-12 13:02:00 得分 0 Robert2001:  
          你结论的后半句说得不对,对不同的进程而言内存指针不能互用,但EXE和加载的DLL同属于一个进程,是少数(唯一?)可以互用的例子。  
  ciba:“在Exe中释放dll的内存,如果该dll还有用,释放掉它的内存合理吗?”  
          当然不行!但这里问题不是这种情况。这里的问题是"如果该dll不再使用,释放掉它的内存合理,但为什么失败?"  
  kylewu:"总之这种方法就是不规范"  
          太武断了,这种机制没什么不规范的,但之所以出问题是实现不规范!  
  其他各位:你们的回答多多少少,局部或全部的,不能令人信服或由此产生怀疑。  
   
  可能是本人孤陋寡闻,请出示试验证据或来源出处(如bugn的多heap说),我们也好互相纠正,共同学习。  
  我同意bugn的   “如果用了CRT的内存分配(new,delete,malloc,free,...),你的dll和exe是静态或动态连接CRT的时候必须一致。”  
  失败可能因为,1)EXE和DLL中的new/delete在其中一处(EXE/DLL)被重载过,另一处(DLL/EXE)没有,2)或是因为bugn的多heap说(等待进一步证实),不管哪一种,下面的解法都一样。  
  即:如果你用了new/delete的话,请改成用::new/::delete(全局-未重载的-操作符)。
Top

10 楼bugn(unknown& whoami)回复于 2001-01-12 13:15:00 得分 0 多heap我原来写了个程序做heap   walk测试过的,我也察看了CRT的代码(堆的初始化的启动代码中,   用了个静态变量保存heap   handl供malloc使用),确实是这样的。  
  对于这种问题,我一般的解决办法是这样的:  
   
  dll输出类的new和delete运算符,这样无论你在那里调用都行(任意模块),都是在执行原来dll的malloc,确保用的是同样的heap。  
   
  示例:  
  #ifdef   BUGN_EXPORT  
    #define   BUGN_API   __declspec(dllexport)  
  #else  
    #define   BUGN_API   __declspec(dllimport)  
  #endif  
  class   CFoo{  
  public  
    BUGN_API   void*   operator   new(size_t   size)   {return   ::new   char[size];}  
    BUGN_API   void   operator   delete(void*   p)   {::delete   p;}  
  }  
 
Top

11 楼maze(迷)回复于 2001-01-12 15:10:00 得分 0 bugn(bugn)  
  你写的很有新意不错不错  
  我开始也是用一个输出函数来做的  
  不如你高  
  newx(生命在于不动)   
  说得不错值,非常同意
Top

12 楼casanova(旗舰)回复于 2001-01-12 18:23:00 得分 0 bugn说得不错。每个win32应用程序至少有一个操作系统提供的缺省堆。如果用到C  
  Runtime   Library的程序(比如VC++编出来的程序),还有一个C运行库自己管理的堆。  
  此外,每个程序或DLL都可以自己创建私有堆。多处理器系统中,还可能有MP堆。  
  ecore2遇到的这种错误,一般说来都是因为分配和释放没有在一个堆上。(因为  
  一般没有人会犯把GlobalAlloc()分配出来的内存用delete释放一类的错误的吧)  
  所以我想这可能与你的DLL和EXE,在链接C运行库时的方式有关。比如DLL是静态链接  
  C运行时库,而EXE是动态链接,那么在运行时,DLL内分配的内存一定是分在了C运行  
  时堆;而EXE在释放时则要进行一番查找来决定用哪个函数。vc++   v6.0运行库既可以  
  使用其自己内部的堆管理函数,也可以直接调用操作系统的堆管理函数(heapalloc()  
  系列的函数)。如果是运行于nt或2000,则用heapalloc();否则检查环境变量  
  __global_heap_selected,以决定是用heapalloc,vc6堆函数还是vc5堆函数;还决定  
  不了的话,会检查文件连接标志,如果是由vc++   v6或更高的版本创建的,就使用版本6  
  的堆函数,否则使用版本5的堆函数。  
 
Top

13 楼newx(Royale with Cheese)回复于 2001-01-12 23:55:00 得分 0 用类似COM的Reference   count最好!它是解决由模块申请和释放其它模块的内存的法宝!
Top

14 楼kylewu(水皮)回复于 2001-01-13 17:03:00 得分 0 以前说这个问题,最后得出的结论也是用COM的IMalloc,最安全,最通用,不过效率最低。   :(  
  很多时候为了效率,还是需要用一些不太规范的方法,冒一些险。  
   
  至于多heap的问题,大概就是bugn说的那样了,不过我补充一下,就是如果dll用静态连接msvcrt.dll,那么dll的初始化代码会另外分配一个crt   heap,如果用动态连接,就会用process原来的crt   heap,exe的情况也一样。如果dll静态连接msvcrt.dll,就会有两个crt   heap,那么dll中malloc的内存块对于exe的heap来说是非法的。这可以在CRTDLL.C和DLLCRT0.C里面看到其中的差别。因此并不能保证在dll中分配的内存在exe中能正确的释放。  
   
  我们写dll的目的之一就是代码重用,这种方法不能保证别的exe能不能正确的使用dll的资源,所以我认为这种方法不规范,如果是作为大项目的开发,这种方式不可取。因为其他程序员可能不清楚其中潜在的问题,很容易造成程序的不稳定。  
   
  我还是比较偏向于使用IMalloc的,可能写COM比较多的关系吧。如果不是特别频繁的分配/释放,IMalloc基本上不会造成明显的效率下降。至于频繁的分配/释放,还不如一开始开个缓冲区,减少分配/释放?
Top

15 楼bugn(unknown& whoami)回复于 2001-01-13 17:58:00 得分 0 to   kylewu:  
   
  关于IMalloc确实是好办法,跟前面建议的GlobalAlloc(LocalAlloc)类似,不会出因为在不同的堆做分配和释放操作而出问题。  
   
  另外到提醒我的是你还不如建议他最好把程序结构改一下,把Dll实现的功能完全做成COM组件。关于COM是否会降低效率的问题,在我的项目里我曾仔细考虑过:如果精心的设计一下,减少借口的频繁调用(把功能重新划分),绝对不会有什么问题的。即使大量使用COM组件接口调用,那么开销会增大多少?如果仔细看一下COM的接口定义方式,会发现某种方式下跟普通的输出函数调用没有区别的。  
   
 
Top

16 楼blackhorse18(黑马)回复于 2001-01-13 18:52:00 得分 0 俗话说:"解铃还需系铃人",从程序运行的可靠性来看,最好还是在DLL中增加一个相应的内存释放函数,在EXE中调用,这是比较稳妥的。

====

我试了一下。从动态库导出函数     fa(char**p){   *p=new   char[123]   };  
  在exe文件中有如下代码:      
  char*   x=NULL;  
  fa(&x);  
  delete[]   x;  
  发现不同的编译环境下运行结果不一样。  
   
  1.   dll和exe   都用MFC   Appwizard方式生成,那么运行时没有任何问题。如果把delete语句去掉,则VC报告内存泄漏   123   Bytes。说明一切正常。  
   
  2.   如果exe用   MFC   Appwizard方式生成,   dll用win32方式生成,则运行时会出现象你所说的错误。进一步用单步跟踪,发现mfc方式和win32方式下的new操作符是用不同方式实现的,源程序分别在VC目录的文件   Afxmem.cpp和new.cpp中。有兴趣的话可以自已跟踪一下。  
   
  因为dll输出函数后,并不知道是哪一个 模拟 调用它,因此new和delete配对时最好在一个文件中,这样可以保证一致性。就如你所说从dll中导出一对函数。  
  另一个 解决 方法是把dll和exe都用同一种方法编译(比如都用MFC方式)。我试了一下,把win32程序改为mfc程序并不困难。  
   
  希望对你有所帮助。

===

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值