ACG狂人

其实我更爱姐汁...

析构过程中内存相关错误的绝大多数原因

今天记录一下长久以来屡次犯的错,每次都是换一种方法编码来绕过这个问题实现功能的,因为这个问题太过隐蔽,导致今天才发现其中真正的原因...下面进行问题描述:
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 酿妹汁 阅读(3303) 评论(11)  编辑 收藏 引用 所属分类: 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 坏人

dll导出函数 应该是纯C的  回复  更多评论   

# 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的命名方式,项目中存在多种配置,都是统一的。  回复  更多评论   

# re: 析构过程中内存相关错误的绝大多数原因 2013-12-26 13:24 smilelittle

这个常见的错误,“2010-07-08 14:35 酿”说的对。原因在于dll和exe链接了不同基础lib导致,把它们全部设置成一样的,就没问题了。  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理