C# Finalize和Dispose的區別


一:總結

1、Finalize方法(C#中是析構函數,以下稱析構函數)是用於釋放非托管資源的,而托管資源會由GC自動回收。所以,我們也可以這樣來區分 托管和非托管資源。所有會由GC自動回收的資源,就是托管的資源,而不能由GC自動回收的資源,就是非托管資源。在我們的類中直接使用非托管資源的情況很 少,所以基本上不用我們寫析構函數。

2、大部分的非托管資源會給系統帶來很多負面影響,例如數據庫連接不被釋放就可能導致連接池中的可用數據庫連接用盡。文件不關閉會導致其它進程無法讀寫這個文件等等。

實現模型:
1、由於大多數的非托管資源都要求可以手動釋放,所以,我們應該專門為釋放非托管資源公開一個方法。實現IDispose接口的Dispose方法是最好的模型,因為C#支持using語句快,可以在離開語句塊時自動調用Dispose方法。

2、雖然可以手動釋放非托管資源,我們仍然要在析構函數中釋放非托管資源,這樣才是安全的應用程序。否則如果因為程序員的疏忽忘記了手動釋放非托管資源, 那么就會帶來災難性的后果。所以說在析構函數中釋放非托管資源,是一種補救的措施,至少對於大多數類來說是如此。

3、由於析構函數的調用將導致GC對對象回收的效率降低,所以如果已經完成了析構函數該干的事情(例如釋放非托管資源),就應當使用SuppressFinalize方法告訴GC不需要再執行某個對象的析構函數。

4、析構函數中只能釋放非托管資源而不能對任何托管的對象/資源進行操作。因為你無法預測析構函數的運行時機,所以,當析構函數被執行的時候,也許你進行操作的托管資源已經被釋放了。這樣將導致嚴重的后果。

5、(這是一個規則)如果一個類擁有一個實現了IDispose接口類型的成員,並創建(注意是創建,而不是接收,必須是由類自己創建)它的實例對象,則 這個類也應該實現IDispose接口,並在Dispose方法中調用所有實現了IDispose接口的成員的Dispose方法。
只有這樣的才能保證所有實現了IDispose接口的類的對象的Dispose方法能夠被調用到,確保可以手動釋放任何需要釋放的資源。

 

二:實現 Finalize 和 Dispose 以清理非托管資源

http://msdn.microsoft.com/zh-cn/library/b1yfkh5e(VS.80).aspx

 

http://www.sudu.cn/info/index.php?op=article&id=12170

三:維護內部非托管資源的托管類的手段:Finalize()--終結Dispose()--處置

非托管資源:原始的操作系統文件句柄,原始的非托管數據庫連接,非托管內存或其他非托管資源。

Finalize()特性:

  • 重寫Finalize()的唯一原因是,c#類通過PInvoke或復雜的COM互操作性任務使用了非托管資源(典型的情況是通過System.Runtime.InteropServices.Marshal類型定義的各成員)注:PInvoke是平台調用服務。
  • object中有finalize方法,但創建的類不能重寫此方法,若Overide會報錯,只能通過析構函數來達到同樣的效果。
  • Finalize方法的作用是保證.NET對象能在垃圾回收時清除非托管資源。
  • 在CLR在托管堆上分配對象時,運行庫自動確定該對象是否提供一個自定義的Finalize方法。如果是這樣,對象會被標記為可終結的,同時一個指向這個對象的指針被保存在名為終結隊列的內部隊列中。終結隊列是一個由垃圾回收器維護的表,它指向每一個在從堆上刪除之前必須被終結的對象。
  • 注意:Finalize雖然看似手動清除非托管資源,其實還是由垃圾回收器維護,它的最大作用是確保非托管資源一定被釋放
  • 在結構上重寫Finalize是不合法的,因為結構是值類型,不在堆上,Finalize是垃圾回收器調用來清理托管堆的,而結構不在堆上。

Dispose()特性:

  • 為了更快更具操作性進行釋放,而非讓垃圾回收器(即不可預知)來進行,可以使用Dispose,即實現IDispose接口.
  • 結構和類類型都可以實現IDispose(與重寫Finalize不同,Finalize只適用於類類型),因為不是垃圾回收器來調用Dispose方法,而是對象本身釋放非托管資源,如Car.Dispose().如果編碼時沒有調用Dispose方法,以為着非托管資源永遠得不到釋放。
  • 如果對象支持IDisposable,總是要對任何直接創建的對象調用Dispose(),即有實現IDisposable接口的類對象都必須調用Dispose方法。應該認為,如果類設計者選擇支持Dispose方法,這個類型就需要執行清除工作。記住一點,如果類型實現了IDisposable接口,調用Dispose方法總是正確的。
  • .net基類庫中許多類型都實現IDisposable接口,並使用了Dispose的別名,其中一個別名如IO中的Close方法,等等別名。使得看起來更自然。
  • using關鍵字,實際內部也是實現IDisposable方法,用ildasm.exe查看使用了using的代碼的CIL,會發現是用try/finally去包含using中的代碼,並且在finally中調用dispose方法。

個人總結:

相同點:

  • 都是為了確保非托管資源得到釋放。

不同點:

  • finalize由垃圾回收器調用;dispose由對象調用。
  • finalize無需擔心因為沒有調用finalize而使非托管資源得不到釋放,而dispose必須手動調用。
  • finalize雖然無需擔心因為沒有調用finalize而使非托管資源得不到釋放,但因為由垃圾回收器管理,不能保證立即釋放非托管資源;而dispose一調用便釋放非托管資源。
  • 只有類類型才能重寫finalize,而結構不能;類和結構都能實現IDispose.原因請看Finalize()特性

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM