【雜談接口】接口對象的生命周期-對象所占用的內存塊清理


【概述】

相信經常使用接口的朋友們,經常碰到訪問違規異常(Access violation),很多情況下無法理解,認為是編譯器的Bug,然后去繞開它,不追其根源,把責任推給IDE,推給編譯器(其實本人以前也經常這樣想)。其實每個異常都是有原因的,碰到這種問題不要繞開,如果目前無法解決,至少要清楚的知道它出現的起因,不放過每一次追根到底的機會。這才是做程序員的應有的心態。(好像有點扯遠了…)

 

【問題描述】

今天公司外包模塊中,外包人員反應出現一個很奇怪的問題,說模塊中無故出現了AV異常。調試果然如此,而且每次都能出現,每次都能出現的異常就好解決,

最初的代碼如下:

一個點擊按鈕事件中包含如下一段代碼:

 

begin
  ....
  (TmBeanFrameVars.GetBean('ef_pcy_frmTree'as INormalSelector).executeSelect(lvPass);
  ....
end;

這樣程序在退出函數的時候引發了一個AV異常(end;運行之后),這時候一般對接口不了解的都無從下手。也無從下手進行調試。

 

【問題分析】

首先上面這句簡單的訪問其實會出現接口的臨時變量,而這個變量在函數退出的時候會執行清理,因為executeSelect函數中釋放了插件的實例,然后清理臨時接口變量時會觸發接口對象的__release方法。這個時候引發的一個異常。

我改造一下代碼,讓錯誤在函數退出之前出現,完整代碼如下。

I`VNO]}GF`0}M_PHZR9C2{U

我用兩個局部變量,這樣改造后,在執行lvIntf := nil的時候就會出現AV錯誤。

image

我順便把executeSelect代碼貼一下,可以看到這個插件是一個窗體對象實例。在執行這個函數里面會把窗體顯示,然后進行了釋放,然后退出了函數。

 

大概的原因明白后,我們調整下代碼,代碼如下:

PFRPD@W3BOX1E[R2B~V[~K9

注意紅色部分,選取完后(釋放實例后),然后馬上清理接口變量,這個時候,其實內存塊應該還是完整的(個人推測),所以清理時不會出現訪問違規異常。

 

下面我來做個調試證明我的推測

R7$@CSJ6K@)E74)1XGHER@V

看紅色框出來部分,兩個接口變量在釋放完后,和之前的指向的內存塊中值是一樣的(我只獲取了一個值,其實可以進行完整對比),然繼續執行。

{8FA%_B][VZU%_SCWT7%V@U

在看看紅色部分,這個時候(其實執行玩cdsOrgan.Append就出現了),lvIntf指向的內存塊已經被清理了,因為有新的內存申請。所以后面在清理lvIntf := nil的時候出現訪問違規錯誤。

 

好了到了這個時候,我們應該發現引發異常的真正原因了:在清理接口變量時,訪問了一塊不可預知的內存塊,所以導致了訪問違規錯誤。所以請大家在使用接口過程中注意接口的清理工作。

 

*認真閱讀會收獲更多。

 

==========================================

DIOCP官方社區|MyBean官方社區

http://www.diocp.org/

==========================================


免責聲明!

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



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