程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C#裡的資源Dispose

C#裡的資源Dispose

編輯:關於C語言

注:這裡的文章從"Zendy---勿在浮沙築高台---"復制,目的是讓我有一個比較充分的對這個問題的認識.

文章標題:對.Net 垃圾回收的C#編程相關方面(Finalize 和Dispose(bool disposing)和 Dispose())的一些理解體會

 

Finalize 和Dispose(bool disposing)和 Dispose() 的相同點:

這三者都是為了釋放非托管資源服務的.

Finalize 和 Dispose() 和Dispose(bool disposing)的不同點:

Finalize是CRL提供的一個機制, 它保證如果一個類實現了Finalize方法,那麼當該類對象被垃圾回收時,垃圾回收器會調用Finalize方法.而該類的開發者就必須在Finalize方法中處理 非托管資源的釋放. 但是什麼時候會調用Finalize由垃圾回收器決定,該類對象的使用者(客戶)無法控制.從而無法及時釋放掉寶貴的非托管資源.由於非托管資源是比較寶貴了,所以這樣會降低性能.
Dispose(bool disposing)不是CRL提供的一個機制, 而僅僅是一個設計模式(作為一個IDisposable接口的方法),它的目的是讓供類對象的使用者(客戶)在使用完類對象後,可以及時手動調用非托管資源的釋放,無需等到該類對象被垃圾回收那個時間點.這樣類的開發者就只需把原先寫在Finalize的釋放非托管資源的代碼,移植到Dispose(bool disposing)中.  而在Finalize中只要簡單的調用 "Dispose(false)"(為什麼傳遞false後面解釋)就可以了.
這個時候我們可能比較疑惑,為什麼還需要一個Dispose()方法?難道只有一個Dispose(bool disposing)或者只有一個Dispose()不可以嗎?
答案是: 
        只有一個Dispose()不可以. 為什麼呢?因為如果只有一個Dispose()而沒有Dispose(bool disposing)方法.那麼在處理實現非托管資源釋放的代碼中無法判斷該方法是客戶調用的還是垃圾回收器通過Finalize調用的.無法實現 判斷如果是客戶手動調用,那麼就不希望垃圾回收器再調用Finalize()(調用GC.SupperFinalize方法).另一個可能的原因(:我們知道如果是垃圾回收器通過Finalize調用的,那麼在釋放代碼中我們可能還會引用其他一些托管對象,而此時這些托管對象可能已經被垃圾回收了, 這樣會導致無法預知的執行結果(千萬不要在Finalize中引用其他的托管對象).

 

        所以確實需要一個bool disposing參數, 但是如果只有一個Dispose(bool disposing),那麼對於客戶來說,就有一個很滑稽要求,Dispose(false)已經被Finalize使用了,必須要求客戶以Dispose(true)方式調用,但是誰又能保證客戶不會以Dispose(false)方式調用呢?所以這裡采用了一中設計模式:重載  把Dispose(bool disposing)實現為 protected, 而Dispose()實現為Public,那麼這樣就保證了客戶只能調用Dispose()(內部調用Dispose(true)//說明是客戶的直接調用),客戶無法調用Dispose(bool disposing).


范例如下:

public class BaseResource: IDisposable
{
  //析構函數自動生成 Finalize 方法和對基類的 Finalize 方法的調用.默認情況下,一個類是沒有析構函數的,也就是說,對象被垃圾回收時不會被調用Finalize方法
  ~BaseResource()     
   {
      // 為了保持代碼的可讀性性和可維護性,千萬不要在這裡寫釋放非托管資源的代碼
      // 必須以Dispose(false)方式調用,以false告訴Dispose(bool disposing)函數是從垃圾回收器在調用Finalize時調用的
      Dispose(false);
   }
  
  
   // 無法被客戶直接調用
   // 如果 disposing 是 true, 那麼這個方法是被客戶直接調用的,那麼托管的,和非托管的資源都可以釋放
   // 如果 disposing 是 false, 那麼函數是從垃圾回收器在調用Finalize時調用的,此時不應當引用其他托管對象所以,只能釋放非托管資源
   protected virtual void Dispose(bool disposing)
   {
     
         // 那麼這個方法是被客戶直接調用的,那麼托管的,和非托管的資源都可以釋放
         if(disposing)
         {
            // 釋放 托管資源
            OtherManagedObject.Dispose();
         }
        
        
         //釋放非托管資源
         DoUnManagedObjectDispose();
        
                
         // 那麼這個方法是被客戶直接調用的,告訴垃圾回收器從Finalization隊列中清除自己,從而阻止垃圾回收器調用Finalize方法.        
         if(disposing) 
           GC.SuppressFinalize(this);  
          
   } 
  
   //可以被客戶直接調用
   public void Dispose()
   {
     //必須以Dispose(true)方式調用,以true告訴Dispose(bool disposing)函數是被客戶直接調用的
      Dispose(true);     
   }
}

上面的范例達到的目的:

1/ 如果客戶沒有調用Dispose(),未能及時釋放托管和非托管資源,那麼在垃圾回收時,還有機會執行Finalize(),釋放非托管資源,但是造成了非托管資源的未及時釋放的空閒浪費

2/ 如果客戶調用了Dispose(),就能及時釋放了托管和非托管資源,那麼該對象被垃圾回收時,不回執行Finalize(),提高了非托管資源的使用效率並提升了系統性能


可以參考SqlConnection對象的New, Open, Close(內部調用Dispose())的使用經歷可以加深對他們的理解.謝謝!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved