C#垃圾回收Finalize 和Dispose的理解

C# 中的析構函數其實是重寫了 System.Object 中的虛方法 Finalize

三種最常的方法以下: 數據庫

  1. 析構函數;(由GC調用,不肯定何時會調用) 函數

  2. 繼承IDisposable接口,實現Dispose方法;(能夠手動調用。好比數據庫的鏈接,SqlConnection.Dispose(),由於若是及時釋放會影響數據庫性能。這時候會用到這個,再如:文件的打開,若是不釋放會影響其它操做,如刪除操做。調用Dispose後這個對象就不能再用了,就等着被GC回收。) 性能

  3. 提供Close方法。(相似Dispose可是,當調用完Close方法後,能夠經過Open從新打開) this

  析構函數不能顯示調用,而對於後兩種方法來講,都須要進行顯示調用才能被執行。而Close與Dispose這兩種方法的區別在於,調用完了對象的Close方法後,此對象有可能被從新進行使用;而Dispose方法來講,此對象所佔有的資源須要被標記爲無用了,也就是此對象要被銷燬,不能再被使用。例如常見.Net類庫中的SqlConnection這個類,當調用完Close方法後,能夠經過Open從新打開一個數據庫鏈接,當完全不用這個對象了就能夠調用Dispose方法來標記此對象無用,等待GC回收。明白了這兩種方法的意思後,你們在往本身的類中添加的接口時候,不要歪曲了這二者意思。 spa

析構函數 對象

Dispose方法 繼承

Close方法 接口

意義 隊列

銷燬對象 資源

銷燬對象

關閉對象資源

調用方式

不能被顯示調用,在GC回收是被調用

須要顯示調用

或者經過using語句

須要顯示調用

調用時機

不肯定

肯定,在顯示調用或者離開using程序塊

肯定,在顯示調用時

  下面提供一個模式來結合上面的 析構函數和Dispose方法。

  public class BaseResource: IDisposable

  {

  //前面咱們說了析構函數其實是重寫了 System.Object 中的虛方法 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(),提升了非託管資源的使用效率並提高了系統性能

  最後:

  若是您的類中使用了非託管資源,則要考慮提供Close方法,和Open方法。並在您的Dispose方法中先調用 Close方法。

  在使用已經 有類時,如SqlConnection。若是暫時不用這個鏈接,能夠考慮用Close()方法。若是不用了就考慮調用

  Dispose()方法。

相關文章
相關標籤/搜索