日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

C# 托管资源和非托管资源(Dispose、析构函数)

發(fā)布時間:2023/12/9 C# 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C# 托管资源和非托管资源(Dispose、析构函数) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

https://www.cnblogs.com/herenzhiming/articles/9691524.html

資源分類:

托管資源指的是.NET可以自動進行回收的資源,主要是指托管堆上分配的內存資源。托管資源的回收工作是不需要人工干預的,有.NET運行庫在合適調用垃圾回收器進行回收。

非托管資源指的是.NET不知道如何回收的資源,最常見的一類非托管資源是包裝操作系統(tǒng)資源的對象,例如文件,窗口,網(wǎng)絡連接,數(shù)據(jù)庫連接,畫刷,圖標等。這類資源,垃圾回收器在清理的時候會調用Object.Finalize()方法。默認情況下,方法是空的,對于非托管對象,需要在此方法中編寫回收非托管資源的代碼,以便垃圾回收器正確回收資源。

析構函數(shù)、Dispose函數(shù):

在.NET中,Object.Finalize()方法是無法重載的,Object.Finalize()可以釋放非托管資源(編譯器是根據(jù)類的析構函數(shù)來自動生成),不能在析構函數(shù)中釋放托管資源。 因為析構函數(shù)是有垃圾回收器調用的,可能在析構函數(shù)調用之前,類包含的托管資源已經(jīng)被回收了,從而導致無法預知的結果。

本來如果按照上面做法,非托管資源也能夠由垃圾回收器進行回收,但是非托管資源一般是有限的,比較寶貴的,而垃圾回收器是由CRL自動調用的,這樣就無法保證及時的釋放掉非托管資源,因此定義了一個Dispose()方法,讓使用者能夠手動的釋放非托管資源。Dispose()方法釋放類的托管資源和非托管資源,使用者手動調用此方法后,垃圾回收器不會對此類實例再次進行回收。Dispose()方法是由使用者調用的,在調用時,類的托管資源和非托管資源肯定都未被回收,所以可以同時回收兩種資源。

Microsoft為非托管資源的回收專門定義了一個接口:IDisposable,接口中只包含一個Dispose()方法。任何包含非托管資源的類,都應該繼承此接口。在一個包含非托管資源的類中,關于資源釋放的標準做法是:

(1) 繼承IDisposable接口;

(2) 實現(xiàn)Dispose()方法,在其中釋放托管資源和非托管資源,并將對象本身從垃圾回收器中移除(垃圾回收器不在回收此資源);

(3) 實現(xiàn)類析構函數(shù),在其中釋放非托管資源。

如果類實現(xiàn)了IDisposable接口,實例化類時可以使用using關鍵字,則當超出using關鍵字作用域時會隱式調用Dispose函數(shù)。

using(CTest inst = new CTest()) { //Do Something; }

顯示調用Dispose()方法:

可以及時的釋放資源,同時通過移除Finalize()方法的執(zhí)行,提高了性能;如果沒有顯示調用Dispose()方法,垃圾回收器也可以通過析構函數(shù)來釋放非托管資源,垃圾回收器本身就具有回收托管資源的功能,從而保證資源的正常釋放,只不過由垃圾回收器回收會導致非托管資源的未及時釋放的浪費。

垃圾處理器調用析構:

在.NET中應該盡可能的少用析構函數(shù)釋放資源。在沒有析構函數(shù)的對象在垃圾處理器一次處理中從內存刪除,但有析構函數(shù)的對象,需要兩次,第一次調用析構函數(shù),第二次刪除對象。而且在析構函數(shù)中包含大量的釋放資源代碼,會降低垃圾回收器的工作效率,影響性能。所以對于包含非托管資源的對象,最好及時的調用Dispose()方法來回收資源,而不是依賴垃圾回收器。

下面是MSDN對這兩個函數(shù)的建議使用方法:

//MSDN建議// Design pattern for a base class.public class Base : IDisposable{//保證重復釋放資源時系統(tǒng)異常private bool _isDisposed = false;// 析構函數(shù),編譯器自動生成Finalize()函數(shù)由GC自動調用,保證資源被回收。// 最好不要聲明空析構函數(shù),造成性能問題// 如果沒有引用非托管資源就不需要顯示聲明析構函數(shù),會造成性能問題,系統(tǒng)會自動生成默認析構函數(shù)~Base(){// 此處只需要釋放非托管代碼即可,因為GC調用時該對象資源可能還不需要釋放Dispose(false);}//外部手動調用或者在using中自動調用,同時釋放托管資源和非托管資源public void Dispose(){Dispose(true);GC.SuppressFinalize(this); ///告訴GC不需要再次調用}protected virtual void Dispose(bool disposing){if (!_isDisposed){if (disposing){//釋放托管資源}// 釋放非托管資源// 釋放大對象this._isDisposed = true;}}}

下面是通過Reflector工具對上面代碼反射出來的結果,可以看出析構函數(shù)直接被翻譯成Finalize()函數(shù)了,因為Finalize函數(shù)不能被重寫,所以只能用析構函數(shù)的方式實現(xiàn)Finalize方法:

public class Base : IDisposable {// Fieldsprivate bool _isDisposed;// Methodspublic Base();public void Dispose();protected virtual void Dispose(bool disposing);protected override void Finalize(); }

C#中Dispose和Close的區(qū)別!
當我們開發(fā)C#代碼的時候,經(jīng)常碰到一個問題,有些class提供Close(),有些class提供Dispose(),那么Dispose和Close到底有什么區(qū)別?

首先,Dispose和Close基本上應該是一樣的。Close是為了那些不熟悉Dispose的開發(fā)者設計的。因為基本上所有的developer都知道Close是干嗎的(特別是對于那些有C++背景的developer)。

但是當我們寫code時候,如果要實現(xiàn)Close和Dispose的時候,要注意Close和Dispose的設計模式。.net的一些class只提供Close,而且派生自IDisposable,并且隱藏了Dispose方法。是不是覺得很不明白了?

對這些class來說,關鍵在于它們顯式的(explicitly)實現(xiàn)了IDisposable。對于隱式實現(xiàn)來說,你只需要調用"new A().Dispose()",但是對于顯式實現(xiàn)來說,Dispose不會是這個class的成員函數(shù)。唯一的調用方式是你先要cast到 IDisposable才行。(“new A().Dispose()”編譯不過,但是“((IDisposable)new A()).Dispose()”可以編譯過)。所以這樣就符合了設計的要求:提供Close(),隱藏Dispose(),并且實現(xiàn)了 IDisposable接口。

在.net的framework里,Close()被設計成public的,并且在Close()里面call被隱藏的Dispose(); Dispose()去call另一個virtual的Dispose(bool)函數(shù)。所以如果你從這個class繼承,你就必須實現(xiàn)Dispose (bool)方法。

調用者call Close()的時候就會call到你重載的那個Dispose(bool)方法去釋放資源。

請參考 http://blogs.msdn.com/brada/archive/2003/07/06/50127.aspx
注意事項:
1,Close()不應該被定義成virtual。對于這個design pattern,Close()只是用來call那個隱藏的Dispose(),用戶不應該改變Close的behavior。對于這個問題, System.IO.Stream也有設計問題。之所以有問題是為了滿足向后兼容的需求。See http://msdn2.microsoft.com/en-us/library/ms227422.aspx. 文檔里面提到雖然Close()是virtual的,但是不應該被override。

演示代碼如下:

1 using System;2 3 namespace ConsoleApplication4 {5 abstract class MyStream : IDisposable6 {7 public MyStream()8 {9 m_unmanagedResource = Marshal.AllocCoTaskMem(100); 10 m_bitmap = new Bitmap(50, 50); 11 } 12 13 #region IDisposable Members 14 void IDisposable.Dispose() 15 { 16 Dispose(true); 17 GC.SuppressFinalize(this); 18 } 19 20 protected virtual void Dispose(bool isDisposing) 21 { 22 if (!m_disposed) 23 { 24 if (isDisposing) 25 { 26 m_bitmap.Dispose(); 27 } 28 Marshal.FreeCoTaskMem(m_unmanagedResource); 29 m_disposed = true; 30 } 31 } 32 33 public void Close() 34 { 35 ((IDisposable)this).Dispose(); 36 } 37 38 ~MyStream() 39 { 40 Dispose(false); 41 } 42 43 private IntPtr m_unmanagedResource; // Unmanaged resource 44 private Bitmap m_bitmap; // IDisposable managed resources 45 private bool m_disposed; 46 47 #endregion 48 } 49 50 class MyDerivedStream : MyStream 51 { 52 public MyDerivedStream() 53 { 54 m_anotherMemory = Marshal.AllocCoTaskMem(20); 55 m_anotherImage = new Bitmap(24, 24); 56 } 57 58 protected override void Dispose(bool isDisposing) 59 { 60 if (!m_disposed) 61 { 62 if (isDisposing) 63 { 64 m_anotherImage.Dispose(); 65 } 66 67 Marshal.FreeCoTaskMem(m_anotherMemory); 68 base.Dispose(isDisposing); 69 m_disposed = true; 70 } 71 } 72 73 public static void Main(string[] args) 74 { 75 MyStream aStream = new MyDerivedStream(); 76 77 aStream.Close(); // Allowed 78 // aStream.Dispose(); // Cannot compile 79 80 ((IDisposable)aStream).Dispose(); // Allowed 81 82 // 83 // This one works as well, because newStream calls the explicit implemented 84 // IDisposable.Dispose method 85 // 86 using (MyStream newStream = new MyDerivedStream()) 87 { 88 // 89 // Do something 90 // 91 } 92 } 93 94 private IntPtr m_anotherMemory; 95 private Bitmap m_anotherImage; 96 private bool m_disposed; 97 } 98 } 99

總結

以上是生活随笔為你收集整理的C# 托管资源和非托管资源(Dispose、析构函数)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。