如果用了CRT的内存分配(new,delete,malloc,free,...),你的dll和exe是静态或动态连接CRT的时候必须一致。msvcrt.dll用了单独的一个heap的,跟你的静态连接crt时用的heap不相同。
project settings->c/c++->code generation->use runtime library->dll和exe选择要一致

解决方案 »

  1.   

    如果在dll中是用GlobalAlloc()分配的内存,在exe中是可以釋放的
      

  2.   

    用 new 和 delete 的内存不能跨模块。你可以:
    从 DLL 导出一个释放内存的函数,在 EXE 里面凡是从 DLL 分配的内存都用它释放。
      

  3.   

    有效的。crt是在heap中分配的,heap在同一个进程内是有效的。GlobalAlloc是在每个进程的默认heap种分配的,一个进程可以使用多个heap。crt使用单独的heap,刚才我前面说的还有点问题,就是如果是静态连接CRT,那么CRT在每个模块都用一个单独的heap;如果动态连接CRT(msvcrt.dll),那么所有用msvcrt.dll的模块就共享一个heap。
      

  4.   

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

  5.   

    正规的话应该在dll的dllMain函数里来处理,case DLL_PROCESS_ATTACH:
    case DLL_PROCESS_DETACH:两种情况分别处理了dll创建和摧毁,可以在此时分配内存和释放内存。在Exe中释放dll的内存,如果该dll还有用,释放掉它的内存合理吗?
      

  6.   

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

  7.   

    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(全局-未重载的-操作符)。
      

  8.   

    多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;}
    }
      

  9.   

    bugn(bugn)
    你写的很有新意不错不错
    我开始也是用一个输出函数来做的
    不如你高
    newx(生命在于不动) 
    说得不错值,非常同意
      

  10.   

    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的堆函数。
      

  11.   

    用类似COM的Reference count最好!它是解决由模块申请和释放其它模块的内存的法宝!
      

  12.   

    以前说这个问题,最后得出的结论也是用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基本上不会造成明显的效率下降。至于频繁的分配/释放,还不如一开始开个缓冲区,减少分配/释放?
      

  13.   

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

  14.   

    俗话说:"解铃还需系铃人",从程序运行的可靠性来看,最好还是在DLL中增加一个相应的内存释放函数,在EXE中调用,这是比较稳妥的。