C++ 出現異常“.... \debug_heap.cpp Line:980 Expression:__acrt_first_block==header"

我的運行環境爲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)即可(推薦使用此方法)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章