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的頭上。如果你自己的程式出現了這個尷尬的錯誤,面對使用者的詢問,我們該如何解釋?本文就是最好的答案。
相關文章
- GoldenGate 常見錯誤分析(二)Go
- Python 常見的17個錯誤分析Python
- C語言常見錯誤分析 (轉)C語言
- 常見的web錯誤Web
- ORA-7445(ACCESS_VIOLATION)(unable_to_trans_pc)(UNABLE_TO_WRITE)錯誤
- MySQL 常見錯誤MySql
- oracle 常見錯誤Oracle
- 執行遷移檔案報錯: Syntax error or access violation: 1166 ...Error
- 常見的錯誤 SQL 用法SQL
- java jdbc Protocol violation錯誤JavaJDBCProtocol
- Windows環境下的ORA-7445(ACCESS_VIOLATION)和ORA-4030錯誤Windows
- Go 常見錯誤集錦 | 字串底層原理及常見錯誤Go字串
- Go常見錯誤集錦 | 字串底層原理及常見錯誤Go字串
- mysql replication常見錯誤MySql
- Go常見錯誤第15篇:interface使用的常見錯誤和最佳實踐Go
- SQL Server連線中三個常見的錯誤分析SQLServer
- ORACLE常見錯誤程式碼的分析與解決(轉)Oracle
- 新手常見的Python執行時的17個錯誤Python
- 常見的 PostgreSQL 升級錯誤SQL
- js作用域的常見錯誤JS
- Nginx常見錯誤程式碼總結和分析方法Nginx
- MySQL常見錯誤分析與解決方法總結MySql
- 常見的資料分析誤區
- VMware Workstation 不可恢復錯誤:(vmui) Exception 0xc0000005(access violation) has occurred.UIException
- 高階資料分析流程要避免的常見錯誤KG
- MySQL 安裝常見錯誤MySql
- mysql8 常見錯誤MySql
- Oracle之Rman常見錯誤Oracle
- MySQL Replication常見錯誤整理MySql
- Hadoop常見錯誤2Hadoop
- opencv 編譯常見錯誤OpenCV編譯
- 常見的授權錯誤及原因
- 常見的錯誤日誌型別型別
- Git相關 | Git 常見的錯誤Git
- Web開發常見性的錯誤Web
- mdxbuilder打包mdx時的常見錯誤UI
- LoadRunner在執行時常見的提示錯誤和解決方法
- MySQL server has gone away錯誤的一些常見原因分析MySqlServerGo