今天遇到C語言的malloc free失敗問題,因為工程代碼量巨大,定位了半天才發現是DLL的問題,動態鏈接庫裡malloc分配的內存,到主程序中free時崩潰失敗。起初以為是指針越界好或被修改,後來直接改成申請後就free,直接失敗,於是就懷疑是DLL與主程序之間的調用問題。於是總結一下常見失敗問題方便後來者參考。
該free錯誤非常容易定位,也就是一個指針沒有成功執行malloc分配,就直接free肯定會失敗,因為該指針還未經過初始化。例如:
void main() { int* pBuf = NULL; free(pBuf); }
這個free錯誤則不好查找,因為實際的程序往往沒下面的例子這麼簡單,可能從申請到最後釋放跨域多個模塊、大量的處理代碼邏輯,指針初始值被修改掉,也就是說分配的這段內存的“門牌號”被改掉了,那麼free就會失敗。
void main() { int* pBuf = (int*)malloc(250); pBuf++; free(pBuf); }
模塊之間的分配和釋放分離設計,從設計上就是有問題的(至少天緣是如此認為),一般對於此類分享,最好使用共享內存方式,也就是說,分配和釋放均由同一方管理,盡管我們有辦法讓他們實現分配和釋放任務分離。
解決辦法:
1、如果可以改成LIB庫進行靜態鏈接,可以改成LIB調用方式。
2、如果堅持使用DLL調用,可以考慮給DLL裡添加一個專門用於釋放該內存的函數,以便主程序調用。
3、使用可在全局堆分配內存的函數(比如HeapAlloc(GetProcessHeap(),0,size)、HeapFree(GetProcessHeap(),0,p)等等),不過不建議使用,最好還是從架構上調整一下。
比如主程序Project->Setting->C/C++的Use Run-time liberary設置為Debug Multithreaded DLL,而模塊的User Run-time liberary設置為Debug Multithreaded的話,主程序調用釋放free 通過DLL malloc的指針就會失敗,其實這時,如果繼續運行的話,delete DLL生成對象也是失敗的。但是統一成Debug Multithreaded DLL就沒有問題。具體可參考:error LNK2005: "public: void __thiscall 一文。