dll方法调用引发的CrtIsValidHeapPointer错误

来源:互联网 发布:使命召唤ol自由数据 编辑:程序博客网 时间:2024/05/22 17:02

dll方法调用引发的CrtIsValidHeapPointer错误

 (2011-11-21 10:41:08)
转载
标签: 

杂谈

 
文章一

 

从CrtIsValidHeapPointer的实现代码处我们可以得知,这个函数不仅检查了空指针的情况,更重要的是检查了指针地址的有效性。

我遇到的问题: 
释放内存时,弹出assert,报错的函数就是上面提到的这个:CrtIsValidHeapPointer。
可是为什么会报错呢?CrtIsValidHeapPointer的注释上说明了情况:如果要释放的内存地址不是在当前控制的堆的地址范围内,也会报这样的错误。

问题分析: 
1、我的实现是在exe中调用dll的一个方法,这个方法里面里面会分配若干内存,并将数据拷贝到新分配的内存中,传递出去;之后我会在exe中对这部分内存进行释放。
2、同一个进程,难道还有两个堆?如果你的工程Runtime Library选择的是MT(使应用程序使用运行时库的多线程静态版本)类型,那么,是的,确实是这样,dll和exe是分别的两个堆。
3、也就是说,dll中分配的内存只能在dll中进行释放,否则CrtIsValidHeapPointer函数就会报错

起初觉得怎么这样呢?但考虑到不用dll的实现者是不一样的,那么他本身的选择的运行时库的链接方式也可能不一样,非要把他们都放在一个堆上操作反而会使问题变得复杂。CRT的这种处理确实更为合理。


解决方法: 
既然谁分配谁释放,而我要分配的内存大小只有dll自己知道,我只好将分配内存的事情放在了dll中,然后dll再提供一个释放内存的方法。类似:
1、allocAndGetData(CData** ppData);    // 我不喜欢这个函数名
2、freeData(*pData);

 

文章二

_CrtIsValidHeapPointer()在Debug模式下测试一个地址在本地的堆内存中,如果采用共享的方式链接C运行时库那么不会出现什么问题,但是如果采用静态的方式链接C运行时库,那么调用该DLL中的函数时就可能出现问题。提示一个错误.

例如:有两个DLL文件 a.dll ,b.dll 且a.dll采用静态的方式链接C运行时库。

如果 a.dll 中导出一个函数 CString aFun(),按值返回一个字符串。

如果 b.dll 中调用该函数如 CString str=aFun();

b.dll调试运行时将出现错误,提示_CrtIsValidHeapPointer()出错.

在MSDN中查找该函数说明知,当一个DLL采用静态的方式链接到C运行时库时,会创建一个相对于该DLL的堆(Heap),而如果采用共享的方式链接到C运行时库的时候则使用的是应用程序的堆内存。而_CrtIsValidHeapPointer()在 DEBug模式下将确保传入的地址在本地的堆内存中,这样问题就明显了:

a.dll采用静态链接C运行时库,所以会创建一个相对于该DLL的堆内存,这样a.dll中分配的临时变量均在该堆中分配。

再看a.dll中的函数aFun()以值的方式返回了一个字符串,执行到return语句时会创建一个临时的变量作为返回,但此临时变量内存却在a.dll的堆内存中,当在b.dll中调用时,语句CString str=aFun();完成时该临时变量的CString析构函数被调用,会释放内存空间,但此时_CrtIsValidHeapPointer()检测到该内存地址不在本地的堆内存中,产生一个错误。但忽略该错误程序有时对正确运行。

解决的办法是将a.ll采用共享的方式链接到C运行时库。

 

这个错误花了很长时间才找出来,哈哈。。。。

文章三

这是因为dll拥有一个独立于应用程序(调用它的exe)的本地堆,调用过后dll占用的空间即被释放,先前new的内存地址即无效,那么解决此问题时要将dll文件中动态申请内存的时候使用HeapCreate函数而不能使用new操作符,具体说明详见MSDN,以下网址可供参考:
转载来自:http://blog.sina.com.cn/s/blog_5119a7f90100yeqm.html
0 0
原创粉丝点击