2

我有一個典型的訪問衝突:如何找出哪些代碼調用已經卸載的模塊?

access violation at 0x4ebb7456: read of address 0x4ebb7456 

這發生在是在程序的其餘部分已關停創建的線程。

在發生異常時,主線程正在運行System.FinalizeUnits

我發現該地址屬於加載了gdiplus.dll的內存區域。

的問題消失,如果我加入LoadLibrary('gdiplus.dll')調用DPR文件,而無需調用返回的句柄FreeLibrary,而定稿段運行這種方式gdiplus.dll沒有卸載。

如何找出程序的哪一部分創建導致訪問衝突的線程?

有沒有一種方法可以識別調入釋放的內存空間的代碼?

FastMM和madExcept沒有什麼幫助,madExcept錯誤報告窗口顯示出來,但立即再次關閉,並且不寫入日誌文件。

我可以拆分程序,但它是一個不平凡的應用程序,我寧願使用某種調試技術來解決此問題。

+0

你在項目中的任何地方使用'HtmlHelpViewer'單元嗎? –

+0

我搜索了它並得到了0個結果,但是我看到'HHCTRL.OCX'被加載(可能是由第三方組件,我們沒有完整的源代碼)。 –

+0

我記得在HTML幫助查看器中有一些類似的聲音關機問題。當然,這可能不是你的問題。 –

回答

3

跟蹤這個的第一步可能是檢測代碼的哪一部分實際創建線程。在應用程序關閉期間創建一個線程對我來說聽起來像是壞消息,因此我一直在尋找確保根本不會發生的事情。

至於如何做到這一點,我會使用調試器斷點。首先,我將在Windows.pas中執行CreateThread設置斷點,並使用調試DCU運行。查看關閉期間是否觸發斷點。

如果它在關閉期間沒有中斷,那麼該線程是由非Delphi代碼創建的。我的下一步是打開CPU視圖並進入CreateThreadCreateThread的反彙編將從JMP指令開始。進入這個,你將在kernel32.CreateThread。現在在這裏設置一個斷點,看看在關閉期間觸發這個時,調用堆棧是什麼。

+0

'kernel32.CreateThread'斷點在所有線程上觸發,除了我正在尋找的那個。但是我發現它屬於'ace32.dll',它是Sybase Advantage數據庫服務器的數據訪問組件。 –

+0

在'ntdll.CsrNewThread'中設置一個斷點讓我在那裏。 –

+0

不錯,至少你在縮小問題 –

2

我會找到正在加載庫的單元(可能它是您正在使用的組件)並將其添加到項目文件的頂部(或接近頂部)。這將確保它在應用程序關閉後稍後卸載,並應防止AV。

所以,舉例來說,如果你正在使用GdiPlus,你最終會得到這樣的:

program MyProgram; 

uses 
    FastMM4, 
    GdiPlus, // <=== this line inserted 
    Windows, 
    Forms, 
    Controls, 
    Classes, 

這可能掩蓋了可能以後回來灣您一個問題。值得嘗試找出哪個單元試圖調用卸載的DLL以及這樣做。

+1

+1這當然是一種可能的解決方法。 –