Delphi Access Violation錯誤的分析


轉自:http://www.cnblogs.com/delphi7456/archive/2010/11/13/1876180.html
Delphi Access Violation錯誤的分析 Delphi常見的運行期Access Violation錯誤有哪些?如何防止? 任何軟件開發都會遇到這樣的情況:你寫好程序並測試,然后到處發送,結果用戶告訴你它失敗了。 你可能考慮用編譯指令{$D}編譯你的程序——Delphi可以建立一個有助於定位Access Violation錯誤的源代碼的鏡像文件。工程選項對話框(Project|Options|Linker & Compiler)讓你指定你所需要的一切。對於單元文件,debug信息和單元的對象代碼一起記錄在unit文件里了。編譯使用這個單元的程序時,debug信息會增加單元文件的大小而且會增加額外的內存開銷,但是它不會影響最終可執行文件的大小和運行速度。包含debug信息和鏡像文件(Project|Options|Linker)選項的產品只有在{$D+} 編譯指令下才會完成行信息。   Access violation通常只在程序的某一個方面表現出來。當問題第一次出現時,考慮一下用戶進行了什么操作是很重要的,然后從這里尋找突破口。從用戶的角度來看,你的程序中止了他們的工作,由他們來告訴你出現的問題似乎讓你延期解決這個問題了。然而,與用戶交流是你發現問題和改善程序的惟一有效方法。   現在你將可以知道在只給你沖突地址的情況下,如何輕松發現准確路徑、源代碼文件、發生Access violation錯誤的行: “Search - Find Error…”。   當一個運行期Access violation出現時,你的用戶得到的錯誤信息類似於如下情況: Access violation at address <十六進制值> in module <應用程序名> Read of address <十六進制值>   如果你的程序在Delphi IDE里包含debug信息編譯,你可以定位到導致這個錯誤源代碼這一行。 在Delphi程序中,一個最普遍導致Access Violation錯誤的原因是使用了一個沒有被創建的對象。如果第二個地址<十六進制值>是FFFFFFF或0000000,十有八九就是你訪問? 了一個沒有被建立的對象。例如,你調用了一個表單的事件,但這個表單不是自動創建的,也沒有代碼實例化。 procedure TfrMain.OnCreate(Sender: TObject); var BadForm: TBadForm; begin //這里將會產生Access violation BadForm.Refresh; end;   假設BadForm在工程選項“Available Forms”窗口列表里——這個窗口是需要手工創建和釋放的。在上面的代碼里調用BadForm窗口的Refresh方法就會導致Access violation。   如果你在Debugger選項窗口使“Stop on Delphi Exceptions”生效,那么就會彈出下面的信息: The message states that the EAccessViolation has occurred. The EAccessViolation is the exception class for invalid memory access errors.   這是你在設計程序時將會看到的信息,下一個信息框將會出現,然后程序失敗了: Access violation at address 0043F193 in module ’Project1.exe’ Read of address 000000.   第一個十六進制數0043F193是發生Access violation的編譯代碼(Project1.exe)的運行期錯誤的地址。在IDE里選擇菜單項“Search|Find Error…”,在對話框里輸入錯誤發生的地址(0043F193)后點擊“OK”按鈕。Delphi將會重新編譯你的工程文件,然后顯示發生運行期錯誤的那一行代碼,這里就是BadForm.Refresh這一行了。   下面列出了Delphi環境下導致Access violation錯誤的大部分常見原因。這個列表不是也不可能覆蓋所有可能出現的Access violation的情況。請在論壇上發送你的Access violation信息,大家可以試着一起解決這個問題——真正的實際事例一般情況下比列出來的錯誤隱晦得多。 1. 調用一個不存在的對象   如上所述,大部分Access violation的合理原因是使用了沒有被創建或者已經被釋放的對象。為了防止這種類型的Access violation的發生,請確保你訪問的任何對象都首先被創建了。例如,當一個Table定位在一個沒有被創建的data module(從auto-crete窗口里移走了)里,你可能在窗體的OnCreate事件里打開這個表。   在下面的代碼里,在調用一個已經被刪除了的對象(b:TBitmap)事件后,一個Access violation出現了: var b:TBitmap; begin b:=TBitmap.Create; try //對b對象進行一些操作 finally b.free; end; ... //由於b已經被釋放,一個Access violation錯誤將會出現 b.Canvas.TextOut(0,0,’這是一個 Access Violation’); end; 2. 不存在的API參數   如果你試圖給Win API函數傳遞一個不存在的參數將會出現一個Access violation錯誤。解決此類Access violation錯誤的最好方法是查閱Win API幫助,看看這個API函數調用的參數信息以及參數類型。例如,總是保證不給一個緩沖參數傳遞一個無效指針。 3. 讓Delphi釋放   當一個對象擁有另一個對象時,讓它給你做刪除工作。因為默認情況下,所有的窗體(自動創建的)都屬於Application對象。當一個應用程序結束時,它釋放了Application對象,也就釋放了所有窗體。例如,如果你在程序開始時自動創建了兩個窗體(Form1/Unit1和Form2/Unit2),下面的代碼就會導致Access violation錯誤的出現: unit Unit1; ... uses unit2; ... procedure TForm1.Call_Form2 begin Form2.ShowModal; Form2.Free; //Access violation錯誤將會出現 Form2.ShowModal; end; 4. 殺死異常   永遠不要破壞臨時異常對象(E),處理一個異常會自動釋放異常對象。如果你自己手動釋放了異常對象,程序會試圖再次釋放它,那么就會出現Access violation錯誤: Zero:=0; try dummy:= 10 / Zero; except on E: EZeroDivide do MessageDlg(’不能用0做除數!’,mtError, [mbOK], 0); E.free. ////Access violation錯誤將會出現 end; 5. 檢索一個空字符串   一個空字符串是沒有任何數據的。就是說,檢索一個空字符串相當於訪問一個不存在的對象,這將導致Access violation錯誤: var s: string; begin s:=’’; s[1]:=’a’; //Access violation錯誤將會出現 end; 今天我遇到的Access Violation錯誤就是由於檢索一個空字符串造成的 if aModalArray[i].HelpKeyword='背景' then cbbNewParent.Items.Add(aModalArray[i].Caption); 當aModalArray[i].HelpKeyword=’’的時候就引發了異常 避免的方法是先對aModalArray[i].HelpKeyword是否為空進行判斷 6. 直接引用指針 你必須間接引用指針,否則你會改變指針地址並可能會破壞其他存儲單元 : procedure TForm1.Button1Click(Sender: TObject); var p1 : pointer; p2 : pointer; begin GetMem(p1, 128); GetMem(p2, 128); //下一行導致Access violation錯誤 Move(p1, p2, 128); //下一行方法正確 Move(p1^, p2^, 128); FreeMem(p1, 128); FreeMem(p2, 128); end;   這些就是我對運行期Access Violation錯誤的全部建議,我希望你們也能對你們程序出現的Access Violation錯誤提出一些看法。   相信所有讀者都遇到過“Access violation” 的錯誤,如果不是自己的程序,我們有很多人就把責任都推在Bill Gates的頭上。如果你自己的程序出現了這個尷尬的錯誤,面對用戶的詢問,我們該如何解釋?本文就是最好的答案。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM