在不同的模块分配的内存,释放的时候会出现此问题,而此问题,只在Debug模式会提示,Release模式不会提示。但不提示并不代表没有错误,一定要解决之。解决的方法是:在哪个模块分配的内存,就在哪个模块释放。 这个错误有两种可能: 一.释放的问题 1,内存不能跨模块分配和释放,模块分配的内存必须由该模块自己来释放。应该在DLL中再加一个方法,比如MemRelease,主程序调用这个方法来释放内存。
2,就是绕过new和delete,用GlobalAlloc()和GlobalFree()的方法 这个问题有两种情况: 1.链接外部lib出错:当前是Debug模式,但工程属性->Configureation Properties->Linker->Input->Additional Dependencies 中的链接库用的却是Release版本的,这个要仔细检查才行。相同道理,Release的模式下也有错用Debug链接库的问题。 2.ruantime Linbrary 方式选择错误:工程属性->Configureation Properties->C/C++->Code Generation->Runtime Library中的选项有可能与当前的编译方式不符。比如当前是Release模式却选择了Multi-threaded Debug DLL (/MDd),相反当前是Debug模式却选择的是Multi-threaded DLL (/MD)。 今天遇到了这个assert,发现是dll中的一个局部vector释放的时候报的,这个vector是在dll中定义的,然后实在exe中分配的空间(通过引用传参数,然后调用push_back方法),这样,vector释放的时候它会发现dll正在释放一个不是由dll分配的内存,所以就会出此断言,一个临时的解决方案是,在dll中分配,可以通过vector的reserve方法来实现,当然,更好的解决方法是上层避免这种用法
还有在使用mfc时也遇到过这个问题, mfc主程序中引用了一个dll,在dll中动态分配了一个对象,然后在主程序中释放,就会出现问题,是由于程序是静态依赖mfc运行时库的,这样在释放的时候,只查找主程序所在的堆空间,应用程序就认为释放了一个不再堆列表中的地址,而改为动态依赖mfc,程序才会查找依赖的dll中的堆列表,所以就没有问题了 从CrtIsValidHeapPointer的实现代码处我们可以得知,这个函数不仅检查了空指针的情况,更重要的是检查了指针地址的有效性。
我遇到的问题:
问题分析: 起初觉得怎么这样呢?但考虑到不用dll的实现者是不一样的,那么他本身的选择的运行时库的链接方式也可能不一样,非要把他们都放在一个堆上操作反而会使问题变得复杂。CRT的这种处理确实更为合理。
文章二 _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,以下网址可供参考:
问题就出在红色的地方,自定义了一个类 将上面的语句改为
ColHistogram 就可以了,不过现在也不知道为什么 (MSDN)中的这段话 The _CrtIsValidHeapPointer function is used to ensure that a specific memory address is within the local heap. The “local” heap refers to the heap created and managed by a particular instance of the C run-time library. If a dynamically linked library (DLL) contains a static link to the run-time library, then it has its own instance of the run-time heap, and therefore its own heap, independent of the application’s local heap. When _DEBUG is not defined, calls to _CrtIsValidHeapPointer are removed during preprocessing. 看了这段话稍微觉得有点意思了,我在程序中自己申请了本地堆,也有要生成动态连接库的DIB类,要连接c运行库,那么我的ColHistogram的实例必须动态生成,因为它在c运行库中没有对应的堆。比如我添加Cstring str;程序就不会有问题,但是我只知道CString是系统定义的,和c运行库有什么关系我就不清楚了。如果静态链接C运行库,那么,dll就要拥有一个独立于应用程序(调用它的exe)的本地堆(但是我的程序没有),如果没有定义_DEBUG,那么_CrtIsValidHeapPointer将被预处理器移除。大概就是这个样子,上面所说的很多东西我都不确定,只是现在的一种解释。
还有dbgheap.c文件似乎是在dll里,还没有办法看
只是把 调用程序 和 程序库 都编译成release就不会出现这个问题。
本质参考:
[http://topic.csdn.net/u/20071116/09/cc675daa-0ab2-4952-99d0-98f3dd717439.html]
1,内存不能跨模块分配和释放,模块分配的内存必须由该模块自己来释放。应该在DLL中再加一个方法,比如MemRelease,主程序调用这个方法来释放内存。
2,就是绕过new和delete,用GlobalAlloc()和GlobalFree()的方法
自己:使用opencv 2.0 peopledetect.cpp 时,Debug版本出现该问题,通过更改
C/C++配置运行时库多线程调试 DLL (/MDd) 解决了问题。
奇怪的错误,坑死个人啊!!当C++/CLI程序引用了native
lib顺利编译之后,程序启动有可能出现以下错误:
这是ms的一个已知bug,原因: The reason why you get this error is that a winforms application has a managed entry point. The initialization of the native global objects is done by the CRT (C RunTime) startup routine. Since in this case there is no CRT startup routine the MyBoard global object fails to initialize correctly. IDE is specific the entry of ManagedApp as "main". However, using "main" will bypass a lot of CRT's startup initialization. 解决方法: 右键点击项目--->properties--->link--->advanced 把Entry Point从main改为 "?mainCRTStartupStrArray@@$$FYMHP$01AP$AAVString@System@@@Z" 原理: That should re-enable the CRT startup code which initializes the internal CRT variables.That symbol is really the mangled name for "int __clrcall mainCRTStartupStrArray(cli::array^)".
malloc/free
malloc/free是C和C++语言的标准库函数, 可以被覆盖, 需要头文件库函数支持,
malloc标准库函数的作用:分配动态堆内存 用malloc分配的一块内存, 你要用指针访问并且要通过移动指针来访问内存数据
malloc只认字节数, 不管数据类型, 只能返回一个void*,
程序员要把void*强制类型转换成相应的指针类型,
new操作符的作用:分配动态堆内存、初始化对象(调用构造函数) 用new创建的对象, 你可以用成员函数访问, 不用直接访问它的地址空间。 new可以认为是malloc加构造函数的执行, new出来的指针是直接带类型信息的, 不用进行强制类型转换
既然new/delete的功能完全覆盖了malloc/free,
为什么C++不把malloc/free淘汰出局呢? 内存泄漏对于malloc或者new都可以检查出来的, 区别在于new可以指明是那个文件的那一行, 而malloc没有这些信息
如果用free释放“new创建的动态对象”, 那么该对象因无法执行析构函数而可能导致程序出错。
int* p = (int*)malloc(5 * sizeof(int));
void* __cdecl malloc(size_t nSize)
void* __cdecl _nh_malloc_dbg(size_t nSize, int nhFlag, int
nBlockUse, const char * szFileName, int nLine)
void* __cdecl _heap_alloc_dbg(size_t nSize, int nBlockUse, const
char * szFileName, int nLine)
void* __cdecl _heap_alloc_base(size_t size) free(p);
void __cdecl free(void * pUserData)
void __cdecl _free_dbg(void* pUserData, int nBlockUse)
int __cdecl _CrtIsValidHeapPointer(const void* pUserData)
static int __cdecl CheckBytes(unsigned char* pb, unsigned char
bCheck, size_t nSize) // bCheck的值是253, nSize的值是4
void __cdecl _free_base(void* pBlock)
int* a = new int[6];
void* operator new(unsigned int cb)
void* __cdecl _nh_malloc(size_t nSize, int nhFlag) delete a;
void operator delete(void* pUserData)
class Person
int main()
Person* p = new Person();这句代码先调用
delete p;这句代码调用
int main()
Debug调试程序:
cin >> p; 这句代码调用 istream& istream::operator>>(char*
s)
cout << p; 这句代码调用 ostream&
ostream::operator<<(const char* s)
delete p; 这句代码调用 void operator delete(void* pUserData)
_CrtIsValidHeapPointer(pUserData)
在VC++2005中使用Pwlib和Opal库,界面使用WinForm进行开发,编译选项为 /clr
1. Set Linker\Advanced\Entry Point to "" (empty
string) Step 1: Makes sure that the CRT startup code is invoked. This is because, if no entry point is specified, the linker will automatically use mainCRTStartup, which is defined in the CRT libraries. mainCRTStartup will make sure that the global object is initialized correctly. Step 2: Makes sure that the linker will look for the symbol “main”. The linker looks for “main” because mainCRTStartup calls main() in its body. The default option for a Winforms application is Subsystem:Windows and this makes the linker look for WinMain().
//
ManagedWrapper.cpp
// This code verifies that DllMain is not called by the Loader // automatically when linked with /noentry. It also checks some // functions that the CRT initializes. #include <</SPAN>windows.h> #include <</SPAN>stdio.h> #include <</SPAN>string.h> #include <</SPAN>stdlib.h> #include <</SPAN>math.h> #include "_vcclrit.h" #using <</SPAN>mscorlib.dll> using namespace System; public ref class ManagedWrapper { public: static int minitialize() { int retval = 0; try { __crt_dll_initialize(); } catch(System::Exception^ e) { Console::WriteLine(e); retval = 1; } return retval; } static int mterminate() { int retval = 0; try { __crt_dll_terminate(); } catch(System::Exception^ e) { Console::WriteLine(e); retval = 1; } return retval; } }; 经过测试,一切OK!!!! 太爽了,终于可以抛开MFC那笨拙的界面开发工具!! 我现在可以充分利用Winform的快速界面开发功能,底层调用Pwli和Opal来开发视频会议了! 呵呵,我已经连续3天没有睡觉了,今晚终于可以做个好梦了!! malloc和free在教材里不知讲了多少,今天实际用到一处,就出问题了。
案发现场是我用VC++在WINXP下编程,先看这一段代码
比较好的处理方式是这样 即保留malloc时候的初始地址,然后赋给另外一个临时指针。操作时使用后者。free的时候把保留的起始指针free掉,而临时指针只是个变量,置空就可以了。 文章到这里似乎就应该写完了,不过由于johnathan的帮忙, 突然有了下文。 注意警告框中的_CrtIsValidHeapPointer,在MSDN上查到这个函数的说明为: Verifies that a specified pointer is in the local heap (debug version only). int _CrtIsValidHeapPointer(const void *userData);
Parameter:
Return Value: 也就是说仅在debug版本中检查free参数是否为the beginning of an allocated memroy block.
那么就编译一个release版本,果然,运行通过, 没弹出什么警告或错误。但运行通过不等于正常无误,
那么结论就是:free掉非malloc起始地址的指针,在debug版本中会出错警告,而在release版本中不会弹出警告但仍然是有错的。所以,还是推荐使用第三段代码的用法
检查指针有效性
_ASSERTE(_CrtIsValidPointer( address, size, TRUE ); _ASSERTE(_CrtIsValidPointer( myData ); ======== //从CSDN.NET
如果是:Debug
The 代码一气呵成,但运行的时候会出现_CrtIsValidHeapPointer的异常,跟进去调了一上午的Bug,终于搞定
跟踪定位到
_CrtIsValidHeapPointer ,注意到 g 8h"@dbgheap.c 文件中
_CrtIsValidHeapPointer 处注释:
程序崩溃在当析构一个带有vector成员函数对象的时候,在析构vector时,会出现这个错误,大致原因是因为析构的时候找不到vector分配的空间 一行一行查看代码发现,对象里面的points2, status等vector变量是在calcOpticalFlowPyrLK(img1, img2, points1, points2, status, similarity, window_size, level, term_criteria, lambda, 0); 函数中分配的,即opencv的dll,所以当对象进行析构的时候,因为不能访问此local heap所以会有异常崩溃。
解决方法: 在调用opencv的函数之前,自己进行空间的分配
|
|