.NET 清理非托管資源
- Dispose
 
類型的 Dispose 方法應(yīng)釋放它擁有的所有資源。它還應(yīng)該通過調(diào)用其父類型的 Dispose 方法釋放其基類型擁有的所有資源。該父類型的 Dispose 方法應(yīng)該釋放它擁有的所有資源并同樣也調(diào)用其父類型的 Dispose 方法,從而在整個基類型層次結(jié)構(gòu)中傳播此模式。若要確保始終正確地清理資源,Dispose 方法應(yīng)該可以被多次調(diào)用而不引發(fā)任何異常。Dispose 方法應(yīng)該為它處置的對象調(diào)用 GC.SuppressFinalize 方法。如果對象當(dāng)前在終止隊(duì)列中,GC.SuppressFinalize 防止其 Finalize 方法被調(diào)用。請記住,執(zhí)行 Finalize 方法會大大減損性能。如果您的 Dispose 方法已經(jīng)完成了清理對象的工作,那么垃圾回收器就不必再調(diào)用對象的 Finalize 方法。
- 設(shè)計(jì)原則
 
應(yīng)用程序或類庫應(yīng)只允許一個線程擁有資源的生存期,并且應(yīng)在不再需要資源時(shí)調(diào)用 Dispose。根據(jù)資源的不同,在處置資源時(shí)進(jìn)行異步線程訪問可能會帶來安全風(fēng)險(xiǎn)。開發(fā)人員應(yīng)仔細(xì)檢查自己的代碼,以確定最佳的方法來強(qiáng)制線程安全。
- 代碼示例
 
- public class BaseResource: IDisposable
 - {
 - // 非托管資源 private IntPtr handle;
 - // 托管資源 private Component Components;
 - // 對象是否已被釋放的標(biāo)志 private bool disposed = false;
 - public BaseResource() { }
 - // 釋放資源,對外開放的可調(diào)用的方法
 - public void Dispose()
 - {
 - // 釋放資源 Dispose(true);
 - // 指示在析構(gòu)函數(shù)中跳過垃圾回收 GC.SuppressFinalize(this);
 - }
 - // 釋放資源,如果disposing為true,釋放所有的托管資源和非托管資源,如果為false,則僅僅釋放非托管資源,這主要是為了避免在析構(gòu)函數(shù)中重復(fù)2次進(jìn)行垃圾回收
 - protected virtual void Dispose(bool disposing)
 - {
 - // 檢查該對象是否已經(jīng)被釋放了
 - if(!this.disposed)
 - {
 - if(disposing)
 - {
 - // 釋放托管資源 Components.Dispose();
 - }
 - // 釋放非托管資源 CloseHandle(handle);
 - handle = IntPtr.Zero;
 - }
 - // 標(biāo)記該對象為已被釋放的對象 disposed = true;
 - }
 - // 析構(gòu)函數(shù),又名終結(jié)器
 - ~BaseResource()
 - {
 - // 釋放非托管資源,在調(diào)用終結(jié)器方法時(shí)系統(tǒng)自動會對托管的資源進(jìn)行垃圾回收
 - Dispose(false);
 - }
 - // 允許多次調(diào)用Dispose,但會拋出異常publicvoid DoSomething()
 - {
 - if(this.disposed)
 - {
 - thrownew ObjectDisposedException();
 - }
 - }
 - }
 
- 實(shí)現(xiàn) Close 方法
 
對于類型來說,若調(diào)用 Close 方法比調(diào)用 Dispose 方法更容易,則可以向基類型添加一個公共 Close 方法。Close 方法又會調(diào)用沒有參數(shù)的 Dispose 方法,該方法可以執(zhí)行正確的清理操作。在基礎(chǔ)類庫中的所有類的Close方法都是基于該原理構(gòu)造的。
- public void Close()
 - {
 - // 釋放資源
 - Dispose();
 - }
 
Finalize(終結(jié)器)
對于您的應(yīng)用程序創(chuàng)建的大多數(shù)對象,可以依靠 .NET Framework 的垃圾回收器隱式地執(zhí)行所有必要的內(nèi)存管理任務(wù)。但是,在您創(chuàng)建封裝非托管資源的對象時(shí),當(dāng)您在應(yīng)用程序中使用完這些非托管資源之后,您必須顯式地釋放它們。
雖然垃圾回收器可以跟蹤封裝非托管資源的對象的生存期,但它不了解具體如何清理這些資源。對于這些類型的對象,.NET Framework 提供 Object.Finalize 方法,它允許對象在垃圾回收器回收該對象使用的內(nèi)存時(shí)適當(dāng)清理其非托管資源。但是對托管對象就不應(yīng)該實(shí)現(xiàn) Finalize方法,因?yàn)槔厥掌鲿詣忧謇硗泄苜Y源。
默認(rèn)情況下,F(xiàn)inalize 方法不執(zhí)行任何操作。如果您要讓垃圾回收器在回收對象的內(nèi)存之前對對象執(zhí)行清理操作,您必須在類中重寫 Finalize 方法。但是在 C# 或 C++ 編程語言中無法重寫 Finalize 方法,所以在 C# 中可使用析構(gòu)函數(shù)語法實(shí)現(xiàn) Finalize 方法。
Finalize 方法主要是在未能調(diào)用 Dispose 方法的情況下充當(dāng)防護(hù)措施來清理資源。
實(shí)現(xiàn) Finalize 方法或析構(gòu)函數(shù)對性能可能會有負(fù)面影響,因此應(yīng)避免不必要地使用它們。
用 Finalize 方法回收對象使用的內(nèi)存需要至少兩次垃圾回收。當(dāng)垃圾回收器執(zhí)行回收時(shí),它只回收沒有終結(jié)器的不可訪問對象的內(nèi)存。這時(shí),它不能回收具有終結(jié)器的不可訪問對象。它改為將這些對象的項(xiàng)從終止隊(duì)列中移除并將它們放置在標(biāo)為準(zhǔn)備終止的對象列表中。該列表中的項(xiàng)指向托管堆中準(zhǔn)備被調(diào)用其終止代碼的對象。垃圾回收器為此列表中的對象調(diào)用 Finalize 方法,然后,將這些項(xiàng)從列表中移除。后來的垃圾回收將確定終止的對象確實(shí)是垃圾,因?yàn)闃?biāo)為準(zhǔn)備終止對象的列表中的項(xiàng)不再指向它們。在后來的垃圾回收中,實(shí)際上回收了對象的內(nèi)存。
- 封裝資源對象
 
如果您要編寫代碼,而該代碼使用一個封裝資源的對象,您應(yīng)該確保在使用完該對象時(shí)調(diào)用該對象的 Dispose 方法。
- 封裝方式
    
- using語句
 - try/finally塊
 
 















 
 
 







 
 
 
 