一個(gè)類實(shí)例的生成需要經(jīng)過對(duì)象內(nèi)存分配、內(nèi)存初始化、設(shè)置對(duì)象執(zhí)行框架三個(gè)步驟。
編譯器首先調(diào)用System._ClassCreate進(jìn)行對(duì)象內(nèi)存分配、內(nèi)存初始化的工作。而System._ClassCreate調(diào)用TObject類的虛方法NewInstance建立對(duì)象的實(shí)例空間,繼承類通常不需要重載TObject.NewInstance,除非你使用自己的內(nèi)存管理器,因此缺省是調(diào)用TObject.NewInstance。TObject.NewInstance方法將根據(jù)編譯器在類信息數(shù)據(jù)中初始化的對(duì)象實(shí)例尺寸(TObject.InstanceSize),調(diào)用系統(tǒng)缺省的MemoryManager.GetMem過程為該對(duì)象在堆(Heap)中分配內(nèi)存,然后調(diào)用TObject.InitInstance方法將分配的空間初始化。InitInstance方法首先將對(duì)象空間的頭4個(gè)字節(jié)初始化為指向?qū)ο箢惖?/span>VMT的指針,然后將其余的空間清零。如果類中還設(shè)計(jì)了接口,它還要初始化接口表格(Interface Table)。
當(dāng)對(duì)象實(shí)例在內(nèi)存中分配且初始化后,開始設(shè)置執(zhí)行框架。所謂設(shè)置執(zhí)行框架就是執(zhí)行你在Create方法里真正寫的代碼。設(shè)置執(zhí)行框架的規(guī)矩是先設(shè)置基類的框架,然后再設(shè)置繼承類的,通常用Inherited關(guān)鍵字來實(shí)現(xiàn)。
上述工作都做完后,編譯器還要調(diào)用System._AfterConstruction讓你有最后一次機(jī)會(huì)進(jìn)行一些事務(wù)的處理工作。System._AfterConstruction是調(diào)用虛方法AfterConstruction實(shí)現(xiàn)的。在TObject中AfterConstruction中只是個(gè)Place Holder,你很少需要重載這個(gè)方法,重載這個(gè)方法通常只是為了與C++ Builder對(duì)象模型兼容。
最后,編譯器返回對(duì)象實(shí)例數(shù)據(jù)的地址指針。
對(duì)象釋放服務(wù)其實(shí)就是對(duì)象創(chuàng)建服務(wù)的逆過程,可以認(rèn)為對(duì)象釋放服務(wù)就是回收對(duì)象在創(chuàng)建過程中分配的資源。
當(dāng)編譯器遇到destructor關(guān)鍵字通常會(huì)這樣編碼:首先調(diào)用System._BeforeDestruction,而System._BeforeDestruction繼而調(diào)用虛方法BeforeDestruction,在TObject中BeforeDestruction中只是個(gè)Place Holder,你很少需要重載這個(gè)方法,重載這個(gè)方法通常只是為了與C++ Builder對(duì)象模型兼容。
這之后,編譯器調(diào)用你在Destroy中真正寫的代碼,如果當(dāng)前你在撰寫的類是繼承鏈上的一員,不要忘記通過inherited調(diào)用父類的析構(gòu)函數(shù)以釋放父類分配的資源,但規(guī)矩是,先釋放當(dāng)前類的資源,然后再調(diào)用父類的,這和對(duì)象創(chuàng)建服務(wù)中設(shè)置對(duì)象執(zhí)行框架的順序恰好相反。
當(dāng)前類及繼承鏈中所有類中分配的資源全部釋放后,最后執(zhí)行的就是釋放掉對(duì)象本身及一些特別數(shù)據(jù)類型占用的內(nèi)存空間。編譯器調(diào)用System._ClassDestroy來完成這件工作。System._ClassDestroy繼而調(diào)用虛方法FreeInstance,繼承類通常不需要重載TObject.FreeInstance,除非你使用自己的內(nèi)存管理器,因此缺省是調(diào)用TObject.FreeInstance。TObject.FreeInstance繼而調(diào)用TObject.CleanupInstance完成對(duì)于字符串?dāng)?shù)組、寬字符串?dāng)?shù)組、Variant、未定義類型數(shù)組、記錄、接口和動(dòng)態(tài)數(shù)組這些特別數(shù)據(jù)類型占用資源的釋放[4],最后TObject.FreeInstance調(diào)用MemoryManager.FreeMem釋放對(duì)象本身占用的內(nèi)存空間。
很有意思的是,對(duì)象釋放服務(wù)與對(duì)象創(chuàng)建服務(wù)所用方法、函數(shù)是一一對(duì)應(yīng)的,是不是有一種很整齊的感覺?
對(duì)象創(chuàng)建服務(wù)
對(duì)象釋放服務(wù)
System._ClassCreate
System._ClassDestroy
System._AfterConstruction
System._BeforeDestruction
TObject.AfterConstruction(virtual)
TObject.BeforeDestruction(virtual)
TObject.NewInstance(virtual)
TObject.FreeInstance(virtual)
TObject.InitInstance
TObject.CleanupInstance
MemoryManager.GetMem
MemoryManager.FreeMem
還有一點(diǎn)要注意,通常我們不會(huì)直接調(diào)用 Destroy 來釋放對(duì)象,而是調(diào)用 TObject.Free,它會(huì)在釋放對(duì)象之前檢查對(duì)象引用是否為 nil。
posted on 2011-02-06 11:36
shaker(太子) 閱讀(2214)
評(píng)論(0) 編輯 收藏 引用