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的頭上。如果你自己的程序出現了這個尷尬的錯誤,面對用戶的詢問,我們該如何解釋?本文就是最好的答案。
總結
以上是生活随笔為你收集整理的Delphi常见的运行期Access Violation错误分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle介质恢复的内部过程--推断与
- 下一篇: 飞鸽传书是企业网络营销管理专家