天天看點

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

【概述】

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

【問題描述】

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

最初的代碼如下:

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

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

【問題分析】

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

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

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

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

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

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

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

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

注意紅色部分,選取完後(釋放執行個體後),然後馬上清理接口變量,這個時候,其實記憶體塊應該還是完整的(個人推測),是以清理時不會出現通路違規異常。

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

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

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

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

在看看紅色部分,這個時候(其實執行玩cdsOrgan.Append就出現了),lvIntf指向的記憶體塊已經被清理了,因為有新的記憶體申請。是以後面在清理lvIntf := nil的時候出現通路違規錯誤。

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

*認真閱讀會收獲更多。

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

<a href="http://www.diocp.org/">http://www.diocp.org/</a>

繼續閱讀