C#記憶體回收Finalize 和Dispose的理解

來源:互聯網
上載者:User
C# 中的解構函式實際上是重寫了 System.Object 中的虛方法 Finalize

三種最常的方法如下:

  1. 解構函式;(由GC調用,不確定什麼時候會調用)

  2. 繼承IDisposable介面,實現Dispose方法;(可以手動調用。比如資料庫的串連,SqlConnection.Dispose(),因為如果及時釋放會影響資料庫效能。這時候會用到這個,再如:檔案的開啟,如果不釋放會影響其它操作,如刪除操作。調用Dispose後這個對象就不能再用了,就等著被GC回收。)

  3. 提供Close方法。(類似Dispose但是,當調用完Close方法後,可以通過Open重新開啟)

  解構函式不能顯示調用,而對於後兩種方法來說,都需要進行顯示調用才能被執行。而Close與Dispose這兩種方法的區別在於,調用完了對象的Close方法後,此對象有可能被重新進行使用;而Dispose方法來說,此對象所佔有的資源需要被標記為無用了,也就是此對象要被銷毀,不能再被使用。例如常見.Net類庫中的SqlConnection這個類,當調用完Close方法後,可以通過Open重新開啟一個資料庫連接,當徹底不用這個對象了就可以調用Dispose方法來標記此對象無用,等待GC回收。明白了這兩種方法的意思後,大家在往自己的類中添加的介面時候,不要歪曲了這兩者意思。

解構函式

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()方法。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.