1. 程式人生 > >C++中Delete時堆錯誤(Heap Corruption)的原因

C++中Delete時堆錯誤(Heap Corruption)的原因

最近這三四天一直在跟一個bug做鬥爭:程式在執行過程中死掉,Output視窗顯示:

        1.Windows has triggered a breakpoint in ***, This may be due to a corruption of the heap...

        2.Access violation reading location...

        今天下午終於找到了真正的原因。那也就順便把關於這個問題Google到的知識總結一下:

        這些問題均有可能代表程式中出現了堆錯誤。

        而出現堆錯誤的原因主要有 以下兩大類:

        首先是工程設定方面的問題:

        1.在dll中申請的記憶體(new)在exe中釋放了(delete),這時有可能會報堆錯誤;這時需要在dll中匯出一個用於釋放記憶體的函式;

        2.在一個dll中申請的記憶體,在另一個dll中釋放;而這兩個dll使用的執行時庫不同。這時可以如1一樣確保哪個模組申請的記憶體就在那個模組釋放,也可以將兩個工程的執行時庫設定成同一個,即MD(d)或者MT(d);

        第二類是程式碼邏輯中的問題:

        1.同一塊地址的指標被釋放(delete)了兩次,會導致以上錯誤。一般地,在每次釋放記憶體之後,都將相應指標設定為NULL,並在delete指標之前進行檢查,可以避免這種問題;

        2.記憶體申請之後,又對相應指標進行了改變,例如自增的(++)操作,使得指標沒有指向記憶體塊的首地址,也會出現這種錯誤。一般地,在申請到記憶體後需要指標運算的,拷貝一份指標變數進行運算,而原指標變數則保持不變。

        我遇到的問題是屬於第二類的第一種,但是涉及到了多執行緒的問題,比較隱蔽。具體是這樣的:

        有四個佇列A1,A2,B1,B2,有兩個執行緒需要通過一個類D的函式將A1,A2中的資料取出來,並複製一份,放入B1,B2。我在類D中定義了一個成員變數M用於臨時存放A1,A2中的資料。當第一個執行緒將A1中資料賦給M之後,還沒有將M放入B1之前,可能第二個執行緒就把M又賦成了A2中的資料。這樣最後存放入B1,B2就是同一份資料,也就是兩個指標指向了同一塊記憶體。這樣,在釋放記憶體的時候,就會出現delete兩次同一塊記憶體的情況了。

        這種情況下,給成員變數M加鎖,或者使用兩個成員變數分別對應兩個執行緒,都可以解決這個問題。