转析构过程中内存相关错误的绝大多数原因
1std::map<std::string, Value> keyValue; // 在函数内部分配的堆栈对象(局部变量)
2ReadData(keyValue);// 从dll中导出的函数
3keyValue.clear(); // delete中出现assert异常
第一行是在应用程序中的堆栈中分配的内存空间。
第二行是我自己写的dll库,用来读取一些数据加入到keyValue中。
第三行是清空keyValue,其实如果不写这一行的话,keyValue也会在函数结尾时清空,到那时同样会出现错误。
这一切乍一看没啥问题,keyValue是局部变量,为什么局部变量的释放会出现异常错误呢?这是因为第二行ReadData的缘故。ReadData的逻辑在另外一个可执行模块中,在其中分配的内存空间不一定与当前模块在同一个堆区。
我们知道,std::map是一个树结构的容器,我在ReadData内部往keyValue中添加了数据,keyValue中会在堆区中分配树节点,而这个节点将会在当前模块在keyValue的析构中被释放。也就是说,我无意中在dll模块中分配了堆空间,又无意中在exe模块中企图释放该空间,这样的行为导致错误是不足为怪的。
时刻牢记,在一个模块中分配和释放同一块内存区域,警惕你所看不见的内存分配和释放。
posted on 2010-07-01 15:47 酿妹汁 阅读(1467) 评论(10) 编辑 收藏 引用 所属分类: C++ 、备忘
评论
# re: 析构过程中内存相关错误的绝大多数原因 2010-07-01 17:09 陈梓瀚(vczh)你的错误是因为dll的std::map跟你这里的std::map不是使用同一份代码,而是两份代码。所以不要拿stl的模板容器去跨dll。所以这种时候,你应该去包装一个不能再.h看到实现的StringValueMap然后暴露出来,或者不要用dll直接使用它的代码。 回复 更多评论
# re: 析构过程中内存相关错误的绝大多数原因 2010-07-01 18:30 hxhxd
看到了dll导出了一个wrap std::string 的std:map,严重怀疑std:string的copy-on-write 使得两个模块引用了同一个stringbuffer,然后dll模块的unload或者exe模块的clear都有可能导致对方模块在进一步的操作中access violation. 回复 更多评论
# re: 析构过程中内存相关错误的绝大多数原因 2010-07-01 18:48 坏人
# re: 析构过程中内存相关错误的绝大多数原因[未登录] 2010-07-01 19:34 路人甲
本人喜欢钻牛角尖,博主能否把测试代码发给我(alcoholyi@qq.com)。
另外,你下的结论有误,没有什么exe,dll模块堆空间一说,堆只跟进程有关系,可以简单的理解为同一个进程的dll和exe共享一个堆空间。
回复 更多评论
# re: 析构过程中内存相关错误的绝大多数原因 2010-07-01 21:15 Forrest
我觉得实际上是你的DLL接口设计有问题,从来就没有见到过接口有使用map的,一般接口的定义只使用C语言的接口,遵守资源谁分配谁释放的原则,如果使用C++的接口的话,比如map,资源的分配释放就分不清楚了. 回复 更多评论
# re: 析构过程中内存相关错误的绝大多数原因 2010-07-01 21:28 Forrest
# re: 析构过程中内存相关错误的绝大多数原因 2010-07-02 02:18 Mensch88
完全赞同vczh的观点。lz的ReadData肯定是在另一个库里面编译的,而那个库调用的STL lib与现在的项目不同。这跟模块没有任何关系。
我最近也一直碰到这种情况。使用别人的第三方程序库,Release能跑,而Debug里面一碰到传递string就出错。郁闷。
有谁知道如何能查看第三方库到底link了哪些dll么?
回复 更多评论
# re: 析构过程中内存相关错误的绝大多数原因 2010-07-02 10:33 老安
确实有一种情况,
在window下遇到过,两个dll,在其中一个dll中new一个object,然后在另外一个dll delete,崩溃。
环境是winxp vc6.
很久之前了。
但是你这种玩法是问题复杂化了。 回复 更多评论
# re: 析构过程中内存相关错误的绝大多数原因 2010-07-02 12:28 ebencheung
@你的错误是因为dll的std::map跟你这里的std::map不是使用同一份代码,而是两份代码
严重同意上述观点.template是源代码级的复用.请勿跨二进制使用. 回复 更多评论
# re: 析构过程中内存相关错误的绝大多数原因 2010-07-08 14:35 酿
回LS几位的话...释放内存的时候,系统提示为已经释放过的内存块或是在不同的堆中分配的内存。也许提示的不正确,但是本着谁分配谁释放的原则的话,就算在模块接口上使用std的容器也应该没什么问题。
这方面只要注意在两个模块中使用同样的clib链接方式就可以,分为debug、release、static、dynamic的命名方式,项目中存在多种配置,都是统一的。 回复 更多评论