明輝手游網(wǎng)中心:是一個免費提供流行視頻軟件教程、在線學(xué)習(xí)分享的學(xué)習(xí)平臺!

對于析構(gòu)(Finalization)

[摘要]簡介:這篇文章假定你熟悉我上兩篇文章中(GC101, GC102)提到的”Dispose/Finalize”模式。微軟引入了析構(gòu)模式(pattern of finalization),目的是想使編碼...
簡介:

這篇文章假定你熟悉我上兩篇文章中(GC101, GC102)提到的”Dispose/Finalize”模式。

微軟引入了析構(gòu)模式(pattern of finalization),目的是想使編碼更安全。如果一個開發(fā)者引用了一個對象(Component)的實例而忘記銷毀它(通過調(diào)用Dispose方法),此組件仍然能被GC自動回收。



讓我來講解一些實現(xiàn)析構(gòu)函數(shù)的負(fù)面效應(yīng)(譯注:即對性能產(chǎn)生負(fù)面影響的因素):(對那些沒有實現(xiàn)析構(gòu)函數(shù)的對象來說,以下是不存在的):

1. 對象被放入“析構(gòu)隊列”(finalization queue)時

2. 對象從”析構(gòu)隊列”中移走時

3. 對象被置入”將要被析構(gòu)隊列”(to be finalized queue)中時

4. 組件的析構(gòu)方法要被調(diào)用時

5. 對象從“將要被析構(gòu)的隊列”中移走時

6. 你無法準(zhǔn)確知道GC要調(diào)用析構(gòu)方法(進行資源回收)的時間

這幾點概述了關(guān)于使用析構(gòu)方法時的影響。正如你所見,析構(gòu)方法對性能有著巨大的沖擊。以下讓我們繼續(xù)深度探討這個問題:



一個析構(gòu)線程

以上幾點中對性能影響最大的就是第4點。.NET的垃圾回收機制有一個專門從“to be finalized queue”調(diào)用其析構(gòu)函數(shù)的工作線程。這個線程以高優(yōu)先級運行,因此如果有很多組件需要釋放資源(析構(gòu)),這個工作線程就會阻塞它們以低優(yōu)先級執(zhí)行。如果有很多垃圾要回收,你的進程就會受到拒絕服務(wù)攻擊(DOS)!



入隊/出隊

以上提到入隊/出隊會對性能造成沖擊。對簡單的對象來說,這是可以接受的。但如果想精確控制它對性能造成的影響,那么就要手工清除了。

你無法控制GC何時執(zhí)行Finalize()。你只知道它何時應(yīng)該清理垃圾:當(dāng)資源不再需要,并且清理垃圾所造成的影響是可以接受的。通過在Dispose()或Close()方法中寫入代碼,你就能在最洽當(dāng)?shù)臅r機進行手工清理資源。



不要引用任何對象

你不能在Finalize()中引用任何已命名的對象。這是因為對象回收是以不可預(yù)知的次序執(zhí)行的,因此你不知道所引用的對象是否之前已被回收掉。這會令你在實現(xiàn)析構(gòu)時受到某種限制。



降級的垃圾回收(Overall degraded garbage collection)

GC需要經(jīng)歷幾個周期才能將析構(gòu)對象回收。這種影響比它當(dāng)初看起來的要大得多,不僅會使你的對象存活更久,而且對那些它引用的對象也會如此。

當(dāng)GC將對象置于”to be finalized queue”中時,它會將GC升級到第1級。第1級中的對象比第0代的對象更少機會被清理,這樣你的對象所引用的不再 需要的托管/非托管資源就會長時間駐留在內(nèi)存中。



為什么需要實現(xiàn)析構(gòu)函數(shù)?

是否有什么動機在里面呢?當(dāng)然啦,這是“確保”清理你的對象占用的資源。這是唯一需要實現(xiàn)析構(gòu)的原因。如果你的組件使用了資源,它們就要在使用后釋放。如果開發(fā)者顯式地調(diào)用了對象的Dispose()方法(假定你在Dispose中調(diào)用了GC.SuppressFinalize),那么此資源就會被清理掉,而且你不必再擔(dān)心它了!如果一個開發(fā)者忘記調(diào)用對象的Dispose方法,那么GC線程會在調(diào)用析構(gòu)函數(shù)時自動清理資源。但是執(zhí)行析構(gòu)的時間是隨機的,這就不由得你控制了。



結(jié)論:

我看見路分兩條:

1. 把所有清理資源的代理放在Dispose(或Close)方法中,開發(fā)者負(fù)責(zé)所有的對象清理的工作。如果你的對象使用的是非托管資源,這是合理的,因為如果你忘記清理它們,就會造成內(nèi)存泄漏。這還會令開發(fā)者按需要隨時完成清理工作。

2. 實現(xiàn)析構(gòu)函數(shù),而且只清理非托管資源。在Dispose方法中清理所有的托管資源。



受到最廣泛接受的是第2種,但我有些不同,讓我來解釋為什么:

如果開發(fā)者調(diào)用對象的Dispose方法失敗時,在測量時就會造成內(nèi)存泄漏(如果沒有出,那么測試工作就需要重新修正。┰诎l(fā)現(xiàn)一個泄漏后,可以在此處調(diào)用對象Dispose方法。然后就出產(chǎn)生最佳性能。



在一個framework類中,實現(xiàn)析構(gòu)的方法有很多種。我會在以后發(fā)表出來,請留意我的blog。