淺談引用計(jì)數(shù)
前言
作為Delphi程序員,您可以不用看這節(jié)內(nèi)容,但是如果您想更多的了解一些COM內(nèi)部技術(shù),或是在對(duì)象模型與引用模型之間可以進(jìn)行很好的控制的話,筆者更希望你可以抽出些許時(shí)間來看這一切的內(nèi)容,而益處提體的將很明顯,您可以自由的用一些技巧來解決讓您頭疼的問題。好了,繼續(xù)我們今天的交流;
在
組件技術(shù)必備知識(shí)二中,我們對(duì)接口(Interface)進(jìn)行了一些介紹,當(dāng)我們并沒有深入的對(duì)接口的實(shí)現(xiàn)/效率/優(yōu)化等問題進(jìn)行進(jìn)一步的禪述,而了解它們的確對(duì)于我們以后的編程是有很大的幫助的,我們都知道,每個(gè)接口都會(huì)維護(hù)一個(gè)全局變量FRefCount (這是Object Pascal里的變量名稱,如果是在C++里,它維護(hù)的是m_CRef),它專門用來控制接口的生命周期,或是組件的生命周期(組件/接口同樣具有生命周期),當(dāng)然,我們也可以給接口強(qiáng)制給值Nil同樣可以釋放接口,但那是不安全的或是不應(yīng)該被推薦的。在此處之所以將引用技術(shù)做為一個(gè)課題例出來就是希望各位可以對(duì)組件的優(yōu)化、效率方面認(rèn)識(shí)一些。而FRefCount是在_AddRef and _Release中得以實(shí)現(xiàn)的,如下代碼(本節(jié)所有代碼摘自Delphi6中,只要您的參考版本是Delphi4以上,代碼都是相同的)。
function TInterfacedObject._AddRef: Integer;
begin
Result := InterlockedIncrement(FRefCount);
end;
function TInterfacedObject._Release: Integer;
begin
Result := InterlockedDecrement(FRefCount);
if Result = 0 then
Destroy;
end;
從代碼中我們可以看出,接口的生命周期是在_AddRef and _Release兩個(gè)方法中控制的,事實(shí)上,這兩個(gè)方面在組件編程中,就是專門用來控制組件的生命周期(關(guān)于組件生命周期和接口生命周期我們將會(huì)近一步的進(jìn)行說明。),之外它們可以說是沒有意義的,而引用計(jì)數(shù)變量(FRefCount)如果在不考慮組件的生命周期時(shí),也是完全沒有意義的。
AddRef and Release是實(shí)現(xiàn)的一種名為引用計(jì)數(shù)的內(nèi)存管理技術(shù),引用計(jì)數(shù)技術(shù)是使組件自己刪除組件的最簡(jiǎn)單的同時(shí)也是效率最高的方法。COM組件將維護(hù)一個(gè)引用計(jì)數(shù)的變量來對(duì)自己生命周期進(jìn)行管理,當(dāng)客戶從組件獲得一個(gè)接口時(shí),這個(gè)引用計(jì)數(shù)變量會(huì)進(jìn)行增1操作(_AddRef),當(dāng)客戶釋放了對(duì)接口的調(diào)用時(shí),組件會(huì)自動(dòng)的進(jìn)行引用計(jì)數(shù)的減1操作(_Release),在基于Delphi的編程中,我們可以不去考慮什么時(shí)候進(jìn)行調(diào)用這兩個(gè)方法,但是如果您一旦脫離了Delphi的話,您可能必須要考慮什么時(shí)候調(diào)用這兩個(gè)方法,如在C++中,您就一定要自己調(diào)用這兩個(gè)方法,這也正是筆者為什么會(huì)寫這一節(jié)的內(nèi)容.簡(jiǎn)單的來說,引用計(jì)數(shù)我們平時(shí)不需要去考慮,但是在對(duì)象引用和接口引用中,您就需要自己去調(diào)用這兩個(gè)方法,同時(shí)它還涉及到作為一個(gè)組件是去整個(gè)的釋放還是單個(gè)的釋放上以及最小單位的釋放上是有必要去考慮引用計(jì)數(shù)的。如:對(duì)于一個(gè)COM組件而言,它封裝了一些COM對(duì)象,但是用戶通過接口可能需要調(diào)用COM組件中的幾個(gè)COM對(duì)象提供的服務(wù),那么問題就產(chǎn)生了,用戶有可能在訪問完了一個(gè)COM對(duì)象再去訪問另一個(gè)COM對(duì)象或是進(jìn)行互動(dòng)的方式進(jìn)行訪問,很不幸運(yùn)的是這個(gè)組件又是一個(gè)占用內(nèi)存資用很大的組件,特別提體到用戶所訪問的兩個(gè)或是更多的COM對(duì)象的同時(shí),您如何對(duì)組件進(jìn)行有效的管理呢?是用戶訪問完了一個(gè)COM對(duì)象之后就立馬釋放這個(gè)COM對(duì)象呢?還是當(dāng)用戶對(duì)組件訪問完成之后再進(jìn)行組件級(jí)的釋放呢?或是您更詳細(xì)的對(duì)每一個(gè)用戶已經(jīng)不用的接口進(jìn)行釋放呢?這都對(duì)組件的效率有些許影響。而此時(shí)我們選擇不同的方式就有可能需要自己增加引用計(jì)數(shù)變量進(jìn)行控制了,如:
var
oFRefCount : Integer;//對(duì)象一級(jí)的引用計(jì)數(shù)的應(yīng)用
begin
…….
end;
var
cFRefCount : Integer;//組件一級(jí)的引用計(jì)數(shù)的應(yīng)用。
begin
……
end;
或是直接引用FRefCount//接口一級(jí)的應(yīng)用計(jì)數(shù)的應(yīng)用。