我的运行环境为VS2017+Opencv4.0.0beta
findNonZero函数出现的调用异常问题如下:
错误:File: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp
Line: 980
Expression: __acrt_first_block == header
For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.
以下是网上一些大神给出的解决方案(然而并不能解决我的问题)
方案一:
如果使用vector<vector<Point> > contours;
作为findContours的参数,在运行时会得到
Assertion failed (mtype == type0 || (CV_MAT_CN(mtype) == CV_MAT_CN(type0) && ((1 << type0) & f…
原因是标准库里有std::vector 和 Point 和findContours里要用到的vector和Point不是一回事所以,声明的时候要用cv::vector和cv::Point就可以了。
方案二:
“修改了当前程序的vc运行库配置,问题解决。具体方法是:项目-属性-配置属性-C/C++-代码生成-运行库,将其改为“多线程调试(/MTd)”。”
方案三:
在配置属性->常规->MFC的使用中,将在静态库中使用MFC改为在共享DLL中使用MFC。
方案四:
将程序改为:
vector<Mat> contours(100);
Mat hierarchy;
findContours( BW, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE );
方案五:
当一个DLL采用静态的方式链接到C运行时库时,会创建一个相对于该DLL的堆(Heap),而如果采用共享的方式链接到C运行时库的时候则使用的是应用程序的堆内存。而_CrtIsValidHeapPointer()在 DEBug模式下将确保传入的地址在本地的堆内存中。 因此就有理由相信,真有可能是静态链接的问题。所以,我立即尝试将:
项目–属性–配置属性–常规–MFC的使用– 选择在共享DLL中使用MFC ;同时,
项目–属性–配置属性–C/C++–代码生成–运行库–选择 多线程DLL(/MD)。
方案六:
方案七:
通过以上可以看出,网络中从来都不缺少该领域的大神,给出的方案也是非常之多,然而并不能解决我的问题。
以下是我对于我自己程序出现的问题给出的解决方案:
通过对出现的错误:__acrt_first_block == header可以大致的知道是堆内存出现的问题,堆区一般都是用来申请分配动态数组时才会使用,而申请动态数组用的最多的就是使用关键字new[]进行申请分配。而我在程序中并未使用new,哪来的堆区的使用呢,通过查找资料了解到vector可以动态分配内存,因此问题极可能就出现在这上面。通过查阅资料了解到是vector析构异常导致的问题,可以借鉴这篇文章看一下http://www.aiuxian.com/article/p-1722238.html。原文部分如下:
大概是因为 dll 如果静态链接了运行时库,dll 就会拥有独立于应用程序堆(也称作local heap)的运行时堆实例。此时在 dll 外部就不能访问此 local heap,所以也就有上面所出现的异常啦。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 dynamic-link library (DLL) contains a static link to the run-time library, 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.
程序崩溃在当析构一个带有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的函数之前,自己进行空间的分配。
通过阅读该片文章之后,了解到vector 析构异常 opencv Assert _CrtIsValidHeapPointer,只要在调用opencv的函数之前,自己进行空间的手动分配。于是,我对程序进行部分修改,修改程序如下:
vector<Vec4i>hierarchy(10000);
vector<Mat>contours(10000);//手动分配内存空间大小
findContours(Dst, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);
//注意,内存空间不已设置过大,否则也会导致程序崩溃.**
至此,我的程序中调用findNonZero函数时出现的程序崩溃问题已经完美地解决。虽然这次bug调试花了两天多的时间才解决,但是,让我知道对于程序出现同类问题,网上给出的方案不一定能解决你碰到的问题,还是要学会具体问题具体分析,不能将网上的方案进行生搬硬套,这样对于你解决问题是没有任何帮助的。最重要的是对于出现问题以及对于问题的解决方案要养成记录的好习惯,这样不仅可以在网络上实现交流共享,有助于他人学习借鉴,还可以有助于我们下次碰到该类问题时,能快速的解决问题。
验证:
在DLL中定义函数,使用MTd生成
void Print_ZxbTest(string str)
{
cout<< str<<endl;
}
在EXE中调用函数,
string a="aaaaa";
Print_ZxbTest(a);
出现同样的BUG。
1、 将函数声明为
void Print_ZxbTest(const char* str)
{
cout<< str<<endl;
}
在EXE中调用函数,
string a="aaaaa";
Print_ZxbTest(a.c_str());
OK
2、 将DLL使用MDd生成,也同样OK
--------------------------------------------------------------------------------------------------------------------------------------------------
以上转自他人博客,下面为自己解决问题时的总结。
总结:
两种方式解决:
1、在使用OPENCV函数之前自己先分配足够空间,从而避免OPENCV函数再重新分配
2、可以将项目属性的C++选项中代码生成下的运行库改为多线程调试DLL(/MDd)即可(推荐使用此方法)