解決堆損壞的一點心得
問題描述
之前在實現水印提取的過程中,遇到了一個詭異的異常。為了較好的說明出現問題的情況,假定我運行的函數為f(),其代碼如下:
f() { code A;//該段代碼在讀取一個文件中的記錄 for(int i = 0; i < 3; i ++) { code B; } }
程序在運行時出現中斷,中斷信息為:Windows已在ApplicationGUI.exe中觸發一個斷點。其原因可能是堆被損壞,這說明ApplicationGUI.exe中或它所加載的任何DLL中有Bug。
點擊中斷信息框中的繼續,出現如下提示信息:
從中斷信息中可以看出,程序中斷的原因是堆被損壞。百度了一下圖片2中的錯誤信息,大概明白是內存分配出了問題。
解決方案
於是開始使用斷點調試,發現程序中斷的位置不確定,有時在運行code A時中斷,有時在第一次運行code B時中斷,有時在運行完所有代碼,即將退出f函數時中斷。這讓我費了相當長的時間來調試程序。
然而正如上面所說的那樣,使用斷點調試根本無法定位到真正出現問題的代碼語句。因此,我使用了之前用過的“注釋法”。具體做法是,注釋掉for語句完后的所有代碼,在f函數中只保留code A代碼,如果程序出現中斷,則從code A的末尾開始,從后往上逐漸注釋掉code A中的代碼,如果程序沒有出現中斷,說明引起中斷的位置不在code A中,因此要從code A代碼的末尾開始,從后往下逐漸去除掉它下面的代碼的注釋。
在我的這個問題中,當我注釋掉for語句之后的代碼后,程序中斷了,說明引起中斷的代碼就在code A中,依次縮小范圍,最終找到了問題的根源。原來是在讀取文件的時候,聲明的空間小於文件中的內容,因此出現了指針的越界。
總結
這種內存分配和釋放引起的錯誤雖然比邏輯錯誤更加容易發現,但這種錯誤往往也不好定位到具體的位置,因此,在設置到分配內存空間,為指針申請內存的時候,一定要仔細,避免出現上述錯誤。