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

ecore2 2001-01-12 09:49:00
谢谢
...全文
465 点赞 收藏 17
写回复
17 条回复
切换为时间正序
当前发帖距今超过3年,不再开放新的回复
发表回复
Robert2001 2001-01-13
我听课!!!
(好好学习 天天向上)
回复
blackhorse18 2001-01-13
俗话说:"解铃还需系铃人",从程序运行的可靠性来看,最好还是在DLL中增加一个相应的内存释放函数,在EXE中调用,这是比较稳妥的。
回复
bugn 2001-01-13
to kylewu:

关于IMalloc确实是好办法,跟前面建议的GlobalAlloc(LocalAlloc)类似,不会出因为在不同的堆做分配和释放操作而出问题。

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

回复
kylewu 2001-01-13
以前说这个问题,最后得出的结论也是用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基本上不会造成明显的效率下降。至于频繁的分配/释放,还不如一开始开个缓冲区,减少分配/释放?
回复
kylewu 2001-01-12
这个话题以前已经讨论过了,总之这种方法就是不规范,是造成非法操作的诱因之一,最好不要用。 :)

在dll中,new和delete的管理数据和exe是分开的,因此在dll中new的东西到了exe中,虽然指针不是非法,不过在delete的时候就会出错,如果在debug版会出assert fail,如果是release版,可能不会报错,不过很可能造成memory leak或者access violation。
回复
无我无人 2001-01-12
用类似COM的Reference count最好!它是解决由模块申请和释放其它模块的内存的法宝!
回复
ciba 2001-01-12
正规的话应该在dll的dllMain函数里来处理,case DLL_PROCESS_ATTACH:
case DLL_PROCESS_DETACH:两种情况分别处理了dll创建和摧毁,可以在此时分配内存和释放内存。在Exe中释放dll的内存,如果该dll还有用,释放掉它的内存合理吗?
回复
Robert2001 2001-01-12
系统为每一个进程维护一个4G的虚拟内存,你这EXE里的指针所指向的内存根本就不是DLL中的!
最好在你的DLLMAIN 里去释放它。 如果想要实现数据共享的话 ,用内存CreatFileMapping
或者用 #pragma data_("Shared")
volatile You_value
#pragma data_seg()

#pragma comment (Linker,"/Sectioin:Shared,RWS")
回复
bugn 2001-01-12
有效的。crt是在heap中分配的,heap在同一个进程内是有效的。GlobalAlloc是在每个进程的默认heap种分配的,一个进程可以使用多个heap。

crt使用单独的heap,刚才我前面说的还有点问题,就是如果是静态连接CRT,那么CRT在每个模块都用一个单独的heap;如果动态连接CRT(msvcrt.dll),那么所有用msvcrt.dll的模块就共享一个heap。
回复
ab 2001-01-12
用 new 和 delete 的内存不能跨模块。你可以:
从 DLL 导出一个释放内存的函数,在 EXE 里面凡是从 DLL 分配的内存都用它释放。
回复
Smile_Tiger 2001-01-12
如果在dll中是用GlobalAlloc()分配的内存,在exe中是可以釋放的
回复
kinghan 2001-01-12
内存指针还有效吗?
回复
bugn 2001-01-12
如果用了CRT的内存分配(new,delete,malloc,free,...),你的dll和exe是静态或动态连接CRT的时候必须一致。msvcrt.dll用了单独的一个heap的,跟你的静态连接crt时用的heap不相同。
project settings->c/c++->code generation->use runtime library->dll和exe选择要一致
回复
casanova 2001-01-12
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的堆函数。
回复
maze 2001-01-12
bugn(bugn)
你写的很有新意不错不错
我开始也是用一个输出函数来做的
不如你高
newx(生命在于不动) 
说得不错值,非常同意
回复
bugn 2001-01-12
多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;}
}
回复
无我无人 2001-01-12
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(全局-未重载的-操作符)。
回复
发帖
VC/MFC
创建于2007-09-28

1.5w+

社区成员

VC/MFC相关问题讨论
申请成为版主
帖子事件
创建了帖子
2001-01-12 09:49
社区公告

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