- 相關(guān)推薦
關(guān)于C++編程中對象生命周期管理的論文
摘 要:在C++編程過(guò)程中,很容易出現內存泄露等安全問(wèn)題,而導致這些問(wèn)題的核心原因就是在于沒(méi)有管理好對象生命周期。本文主要對C++編程中對象生命周期管理的幾種方式進(jìn)行分析并提出自己的見(jiàn)解。
關(guān)鍵詞:C++編程;對象;生命周期
C++編程中對象生命周期管理主要包括生成、使用和消除三個(gè)階段。對象不僅可以改變自己變量的狀態(tài),而且還擁有使用創(chuàng )建它的那個(gè)類(lèi)中方法的能力,對象通過(guò)使用這些方法可以產(chǎn)生一定的行為。一個(gè)對象的生命周期結束而對象卻沒(méi)被釋放,那么內存泄露問(wèn)題肯定會(huì )產(chǎn)生,因此,做好對象生命周期管理工作非常重要。
1. 業(yè)務(wù)邏輯
從理論上講,應用程序中申請的內存一般都有其作用域,當對象已經(jīng)完成其業(yè)務(wù)邏輯后,需要將其釋放,避免造成內存泄露(全局對象除外)。例如,視圖和文檔,當視圖對象已經(jīng)完成其業(yè)務(wù)邏輯后,用戶(hù)關(guān)閉對應窗口時(shí),需要將其進(jìn)行釋放,而文檔對象可以在所有視圖對象釋放時(shí)釋放。因此,系統代碼就可以直接根據業(yè)務(wù)邏輯來(lái)編寫(xiě),這樣的代碼不僅效率高,而且容易理解。雖然采用這種方法直接編寫(xiě)代碼有很多優(yōu)勢,但是隨著(zhù)需求的不斷增加,系統規模將會(huì )越來(lái)越大,也就越來(lái)越復雜,因此,上述那種簡(jiǎn)單的方法不適用于復雜的系統。例如,在上面的例子中加一個(gè)關(guān)閉文檔的操作,使用這個(gè)命令時(shí),將文檔直接關(guān)閉,可此時(shí)視圖也有可能是開(kāi)著(zhù)的,關(guān)閉文檔需要將視圖先關(guān)閉,在視圖對象釋放時(shí)進(jìn)行文檔釋放,那么此時(shí)用戶(hù)關(guān)閉對應的窗口就變成了視圖對象的釋放條件。在一個(gè)復雜的系統中,一個(gè)對象要想釋放需要滿(mǎn)足很多條件才能實(shí)現,此時(shí)都是按照業(yè)務(wù)邏輯來(lái)判斷程序,出錯則不可避免。由此可知,用業(yè)務(wù)邏輯來(lái)管理對象生命周期的方式僅適用于簡(jiǎn)單對象系統。因此,筆者認為使對象生命周期的管理更加合理和簡(jiǎn)化,需要設計另一些機制。
2. 釋放通知
如果對文檔對象進(jìn)行釋放,將其釋放通知發(fā)送給相關(guān)的視圖對象,其二者關(guān)系是非常密切的。如果視圖對象暫時(shí)不釋放,可以清除文檔對象的引用,如若視圖對象釋放了,其結果也不會(huì )發(fā)生任何變化。當創(chuàng )建好文檔和視圖后,引用是相互的,這里先從單項開(kāi)始,視圖引用文檔:(1)文檔的指針被視圖獲得;(2)文檔的regFreeNotifiC++ation方法被視圖調用,文檔自己將會(huì )充當參數,文檔對象釋放的通知列表中將會(huì )把文檔自己加入其中,也就是說(shuō),文檔對象釋放時(shí),將其釋放的通知,需要讓列表中的所有對象都能夠知道;(3)此時(shí)文檔對象的指針,不會(huì )有什么不穩定的現象產(chǎn)生,視圖對象就可以安安心心、大大方方的擁有;(4)如果文檔對象釋放了,將其通知給所有的列表對象,并且讓所有的對象進(jìn)行調用,由于視圖剛才已經(jīng)注冊過(guò)了,因此視圖也包括在內。對列表中對象的freeNotifiC++ation方法進(jìn)行調用就是通知的方法,充分利用這個(gè)方法,在視圖的這個(gè)方法中,將文檔的引用清除掉;(5)如果先釋放的不是文檔對象,而是視圖對象,此時(shí)文檔對象中的unregFreeNotifiC++ation方法就要被執行,然后從列表中移除自己。
在Delphi語(yǔ)言的VC++L庫中同樣可采用這種方法。上述三個(gè)方法在VC++L的TC++omponent類(lèi)上都被抽象了,只不過(guò)名稱(chēng)不同而已,因此通過(guò)采用這種方法TC++omponent類(lèi)及其子類(lèi)的對象之間可以相互引用,并且能保證像野指針這類(lèi)問(wèn)題是不會(huì )出現的。這種方法雖然有這么多的優(yōu)勢,但是其也具有一定的缺點(diǎn),使其在使用時(shí)受到制約,例如,成本高、效率不高等。因此,這種方法在簡(jiǎn)單、高等級對象中比較適合使用。抽象對象引用以及后續的釋放環(huán)節是釋放通知機制的最大意義,使這個(gè)機制和業(yè)務(wù)邏輯本身無(wú)關(guān)。這樣,無(wú)論業(yè)務(wù)邏輯多么復雜,開(kāi)發(fā)人員只要嚴格遵守這個(gè)機制,都可以確保野指針問(wèn)題不會(huì )出現,從而使開(kāi)發(fā)人員的工作量大大減輕,并且開(kāi)發(fā)效率更高、程序質(zhì)量更好。
3. 引用計數
由上述分析可以看出,釋放通知雖然在生命周期管理中是一個(gè)很好的機制,但是也存在一些不足。例如,每個(gè)對象需要維護一個(gè)列表,可否不對列表進(jìn)行維護,而對其進(jìn)一步抽象呢?在上文中已經(jīng)提出每個(gè)對象釋放時(shí)機都不同,而這些釋放時(shí)機的決定因素有很多,其中業(yè)務(wù)邏輯是最重要的,但是這個(gè)合理的釋放時(shí)機的確定是隨著(zhù)業(yè)務(wù)邏輯的復雜性越來(lái)越復雜,已經(jīng)不是由單一的條件來(lái)決定,而是由多個(gè)條件同時(shí)制約。因此,要想滿(mǎn)足釋放必須滿(mǎn)足所有的條件,解決這個(gè)問(wèn)題的關(guān)鍵在于判斷這些條件。針對對象釋放,只關(guān)心這個(gè)條件能夠滿(mǎn)足釋放要求,而對具體業(yè)務(wù)條件是什么不做重點(diǎn)考慮。因此,誕生了引用計數的機制,每一個(gè)對象由一個(gè)計數器,當加一時(shí)就說(shuō)明釋放的條件并沒(méi)有滿(mǎn)足條件,當減一時(shí)就說(shuō)明釋放條件已經(jīng)滿(mǎn)足條件,如果計數器為0就說(shuō)明所有的條件都滿(mǎn)足,對象可以釋放了。如果文檔被視圖引用的話(huà),那么文檔的addRef方法被視圖調用,計數器增1;若文檔被引用的視圖釋放,則文檔的release方法就被視圖調用,同時(shí)計數器減1。當計數器為0時(shí),文檔對象釋放。但是如果在這個(gè)過(guò)程中文檔被其他視圖使用,那么addRef方法也被那個(gè)視圖執行,這樣就不會(huì )將文檔對象釋放,繼續由那個(gè)視圖使用,如此循環(huán),直到release方法被那個(gè)視圖使用為止。[0]
class BaseRefObject
{
public:
BaseRefObject():m_nRefCount(0)
{
}
void addRef()
{
++m_nRefCount;
}
void release()
{
if (0 == m_RefCount)
{
return;
}
else
{
--m_nRefCount;
this;
}
private:
int m_nRefCount;
}
這種方法優(yōu)勢較明顯,其方式簡(jiǎn)單、效率高,可以在大規模對象系統中使用,但是同時(shí)也存在一些不足,具體表現在以下幾個(gè)方面:(1)文檔對象的釋放都是被動(dòng)的,影響其因素很多,尤其是外界因素,即使業(yè)務(wù)上要求文檔關(guān)閉,它也不會(huì )關(guān)閉,但是可以保持文檔的內容且把其作為一種標志來(lái)放置,從而表明其已經(jīng)關(guān)閉。此時(shí)如果文檔的方法再被視圖調用的話(huà),直接返回錯誤。另外,這個(gè)過(guò)程的完成還可以借助使用事件的機制輔助來(lái)進(jìn)行,就是需要在關(guān)閉時(shí),向視圖發(fā)送事件,讓它將引用解除,這個(gè)步驟又與釋放通知有些相似;(2)循環(huán)引用問(wèn)題。上面的例子都只是假設文檔被視圖引用,而事實(shí)上視圖也可以被文檔引用。那么如果視圖被文檔引用的話(huà),就會(huì )出現兩個(gè)對象相互引用,此時(shí)如果沒(méi)有外力作用,兩個(gè)對象的引用計數都不會(huì )變?yōu)?,于是內存泄漏現象就由此產(chǎn)生了,它的產(chǎn)生是任何開(kāi)發(fā)者都不愿意看到的?傊,引用計數也是一種機制,在微軟的C++OM中這種機制經(jīng)常被使用,它與業(yè)務(wù)邏輯沒(méi)有任何關(guān)系。
4. 垃圾回收
野指針不是NULL指針而是指向非法內存的指針,產(chǎn)生野指針的原因主要有:(1)沒(méi)有初始化指針變量。任何指針變量剛被創(chuàng )建時(shí)不會(huì )自動(dòng)成為NULL指針,它的默認值是隨機的,它會(huì )亂指一氣。因此,指針變量初始化是要么將指針設置為NULL,要么讓它指向有效內存。(2)指針p被free或者之后沒(méi)有置為NULL,讓人誤認為p仍是一個(gè)有效的指針。(3)指針操作超越了變量的作用范圍。其實(shí)避免野指針發(fā)生的一個(gè)簡(jiǎn)單方法就是對象不釋放,但是對象不釋放會(huì )導致另一個(gè)問(wèn)題產(chǎn)生--內存泄露,一旦出現了野指針,程序就會(huì )被迫停止運行,而內存泄露則不會(huì )導致程序立刻停止,它等到?jīng)]有資源再消耗時(shí)才停止。因此,為了避免野指針的發(fā)生,可暫時(shí)不管內存泄露問(wèn)題,等到出現資源不足時(shí)再想其他辦法(如資源不足時(shí),找出那些垃圾,將這些垃圾對象釋放掉,將其內存給其他對象用),這是一個(gè)比較簡(jiǎn)單的方法。查找垃圾所采用的算法如下:首先,假設所有的對象都是垃圾;其次,利用全局變量和局部變量找出非垃圾對象,也就是找出沒(méi)有被它們引用的對象;再次,再從第二步找出的非垃圾對象中找出不是垃圾的對象,其方法就是非垃圾對象引用的對象也不是垃圾;第四步,將第三步驟循環(huán)下去,直到?jīng)]有新的非垃圾對象產(chǎn)生為止;最后,剩下的就都是垃圾。
由此可以看出,這種算法是非常簡(jiǎn)單的,但是在C++中,全局變量、局部變量和成員變量不全是對象,此時(shí)這個(gè)算法就有些不合適了,在JAVA等這些語(yǔ)言中都是對象,此時(shí)需要語(yǔ)言級的支撐。到目前為止,最好的內存管理機制也就是垃圾回收了,其避免野指針的產(chǎn)生是不需要人工來(lái)參與的,它也不會(huì )產(chǎn)生內存泄露等問(wèn)題,其效率是非常高的,但是需要花費大量的成本。
結語(yǔ)
業(yè)務(wù)邏輯決定了對象的生命周期。事實(shí)上,業(yè)務(wù)邏輯是不斷變化的,朝著(zhù)復雜的方向發(fā)展,此時(shí)具體到某個(gè)對象其釋放的條件可能比較復雜,因此,需要對這些對象的生命周期的管理需要引進(jìn)一些專(zhuān)門(mén)的機制來(lái)進(jìn)行,由此,釋放通知、引用計數、垃圾回收等機制就產(chǎn)生了。之所以產(chǎn)生如此多的機制,那是因為沒(méi)有一個(gè)機制能夠完全解決一切問(wèn)題,每個(gè)機制都有優(yōu)點(diǎn)和不足。筆者通過(guò)多年來(lái)的工作和學(xué)習發(fā)現,用的最多的是引用計數,但是在使用的同時(shí),也經(jīng)常會(huì )出現循環(huán)引用的問(wèn)題。由此可見(jiàn),最好的方法就是:將引用計數作為基礎,在合適的地方根據業(yè)務(wù)邏輯加入釋放通知(這里主要使用事件通知,其實(shí)事件本身是為了業(yè)務(wù)的需要而設計,并非是為了對象釋放,但從本質(zhì)上講業(yè)務(wù)決定著(zhù)對象的生命周期)。
生命周期管理中這些機制的引用的原因有很多,其中一個(gè)重要原因就是減少一些內存問(wèn)題的發(fā)生,并且達到高效率、高質(zhì)量的目標。內存泄露是普遍存在且必須解決的問(wèn)題,而本文所提到的這些機制沒(méi)有一個(gè)能真正解決內存泄露問(wèn)題。因此,現階段程序員對此問(wèn)題進(jìn)行更深入的研究,將業(yè)務(wù)邏輯和編程事務(wù)性工作同時(shí)抓,同等程度重視二者。
參考文獻:
. C++omputer Integrated ManufaC++turing Systems-C++IMS, 2004, (01).
【C++編程中對象生命周期管理的論文】相關(guān)文章:
CORBA對象生命周期的論文06-13
鋼材生命周期評價(jià)中GaBi軟件的應用論文07-18
淺談施工企業(yè)項目管理團隊的生命周期建設的論文08-11
淺談產(chǎn)品生命周期對營(yíng)銷(xiāo)渠道管理策略的影響論文10-18
企業(yè)生命周期的知識型員工績(jì)效管理的論文10-27
生命周期廣告策略的分析論文07-01
管理畢業(yè)論文-產(chǎn)品不同生命周期的廣告策略選擇09-04