標籤:
偵錯工具,對動態申請的記憶體用free或者delete釋放時程式崩潰,跳出如下對話方塊:
點擊重試,定位到具體的CRT源碼部分:_ASSERTE(_CrtIsValidHeapPointer(pUserData));
1、原因分析:
查看CRT源碼,一步一步看看裡面都幹了什麼吧: _CrtIsValidHeapPointer----->_CrtIsValidPointer---->HeapValidate
首先在_CrtIsValidPointer中檢測這個指標是否有效,即不為空白;然後調用WIndows API HeapValidate,這個才是關鍵了,CRT 代碼中C++的樂網new 調用的是C語言的malloc,delete調用的是C語言的free。由於C庫函數是跨平台的,那麼CRT的意義就在於在Windows平台上封裝WIN API 來實現這些功能。
HeapValidate功能是檢測一個記憶體指標是否是在這個堆棧上面申請的。每個PE檔案在載入時都會初始化CRT運行庫,調用heapinit.c 中的_heap_init,_heap_init中還是用的WIN API HeapCreate初始化堆棧,然後把這個堆棧的控制代碼儲存到一個全域變數中,後續這個進程在堆棧上申請釋放記憶體都要用到這個控制代碼。上面的崩潰原因就是因為釋放記憶體的指標不是在該PE檔案的堆棧上申請的。
具體說,我的問題其實就是在DLL中申請了一塊記憶體,在EXE中刪除這塊記憶體。但是這兩個PE(exe、dll都是PE檔案)在初始化時分配的堆棧控制代碼是不一樣的,所以就出錯了。
2、解決方案:
問題原因清楚了,其實就是要我們注意,在誰的堆棧上分配的記憶體,就在誰的堆棧上釋放。
方案一:在DLL裡面申請的記憶體,就在DLL裡面釋放,不要由其他模組去釋放;(為了區分第二條,這個前提是exe 和 dll都使用mtd方式編譯)
方案二:讓所有的PE共用一個堆棧控制代碼,所有的模組都採用的mdd方式編譯;
(上面說的是Debug選項下),原因在於,採用mdd編譯時間,所有的模組都會共用同一個msvcr*.dll,堆棧控制代碼作為靜態變數儲存在裡面,所以所有的模組都是同一個堆棧上申請、釋放記憶體,不管哪個模組都可以釋放其他模組申請的記憶體了。而採用mtd編譯時間,所有模組都相當於有自己獨立的一個mscvr*.dll(相當於把msvcr*.dll中需要的代碼都打包到自己裡面去了),因此每個模組在載入的時候都有自己獨立的堆棧,這時去刪除其他模組申請的記憶體,堆棧檢測該指標肯定就是無效的了。
3、後記
碼字好累,語文學的不好,說的有點繞。希望對遇到該問題的人有所協助,謝謝。
VS偵錯工具_ASSERTE(_CrtIsValidHeapPointer(pUserData))崩潰的原因以及解決方案