国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設計 > 正文

.net非托管資源的回收

2019-11-14 16:23:24
字體:
來源:轉載
供稿:網(wǎng)友

釋放未托管的資源有兩種方法

 

1、析構函數(shù)

2、實現(xiàn)System.IDisposable接口

 

一、析構函數(shù)  

構造函數(shù)可以指定必須在創(chuàng)建類的實例時進行的某些操作,在垃圾收集器刪除對象時,也可以調用析構函數(shù)。析構函數(shù)初看起來似乎是放置釋放未托管資源、執(zhí)行一般清理操作的代碼的最佳地方。但是,事情并不是如此簡單。由于垃圾回收器的運行規(guī)則決定了,不能在析構函數(shù)中放置需要在某一時刻運行的代碼,如果對象占用了寶貴而重要的資源,應盡可能快地釋放這些資源,此時就不能等待垃圾收集器來釋放了.  

實例

 
C# 代碼   復制
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; 
namespace MemRelease
{    class PRogram    {        ~Program()        {            // Orders.        }         static void Main(string[] args)        {        }    }} 

 

在IL DASM中,你會發(fā)現(xiàn)并沒有這個析構的方法。C#編譯器在編譯析構函數(shù)時,會隱式地把析構函數(shù)的代碼編譯為Finalize()方法的對應代碼,確保執(zhí)行父類的Finalize()方法 看下這段代碼中對于析構函數(shù)的編譯:

 
C# 代碼   復制
.method family hidebysig virtual instance void 
        Finalize() cil managed
{  // Code size       14 (0xe)  .maxstack  1  .try  {    IL_0000:  nop    IL_0001:  nop    IL_0002:  leave.s    IL_000c  }  // end .try  finally  {    IL_0004:  ldarg.0    IL_0005:  call       instance void [mscorlib]System.Object::Finalize()    IL_000a:  nop    IL_000b:  endfinally  }  // end handler  IL_000c:  nop  IL_000d:  ret} // end of method Program::Finalize 

 

使用析構函數(shù)來釋放資源有幾個問題

 

1、與C++析構函數(shù)相比,C#析構函數(shù)的問題是他們的不確定性。在刪除C++對象時,其析構函數(shù)會立即執(zhí)行,但是由于垃圾收集器的工作方式,無法確定C#對象的析構函數(shù)何時執(zhí)行。

2、C#析構函數(shù)的執(zhí)行會延遲對象最終從內存中刪除的時間。有析構函數(shù)的對象需要2次處理才能刪除:第一次調用析構函數(shù)時,沒有刪除對象,第二次調用才真正刪除對象。

 

二、IDisposable接口

IDisposable接口定義了一個模式,為釋放未托管的資源提供了確定的機制,并避免產(chǎn)生析構函數(shù)固有的與垃圾函數(shù)器相關的問題。IDisposable接口聲明了一個方法Dispose(),它不帶參數(shù),返回void。

 

1、MSDN建議按照下面的模式實現(xiàn)IDisposable接口

 
C# 代碼   復制
 public class Foo: IDisposable
 {     public void Dispose()     {        Dispose(true);        GC.SuppressFinalize(this);     }       protected virtual void Dispose(bool disposing)     {        if (!m_disposed)        {            if (disposing)            {               // Release managed resources            }              // Release unmanaged resources              m_disposed = true;        }     }       ~Foo()     {        Dispose(false);     }       private bool m_disposed; }

 

.NET的對象中實際上有兩個用于釋放資源的函數(shù):Dispose和Finalize

 

(1)、Finalize的目的是用于釋放非托管的資源,而Dispose是用于釋放所有資源,包括托管的和非托管的

 

(2)、void Dispose(bool disposing)函數(shù)通過一個disposing參數(shù)來區(qū)別當前是否是被Dispose()調用

如果是被Dispose()調用,那么需要同時釋放托管和非托管的資源。如果是被~Foo()(也就是C#的Finalize())調用了,那么只需要釋放非托管的資源即可。

 

(3)、Dispose()函數(shù)是被其它代碼顯式調用并要求釋放資源的,而Finalize是被GC調用的

GC調用的時候Foo所引用的其它托管對象可能還不需要被銷毀,并且即使要銷毀,也會由GC來調用。因此在Finalize中只需要釋放非托管資源即可。另外一方面,由于在Dispose()中已經(jīng)釋放了托管和非托管的資源,因此在對象被GC回收時再次調用Finalize是沒有必要的,所以在Dispose()中調用GC.SuppressFinalize(this)避免重復調用Finalize。

 

然而,即使重復調用Finalize和Dispose也是不存在問題的,因為有變量m_disposed的存在,資源只會被釋放一次,多余的調用會被忽略過去。

 

Finalize、Dispose保證了

 

(1)、 Finalize只釋放非托管資源;

(2)、 Dispose釋放托管和非托管資源;

(3)、 重復調用Finalize和Dispose是沒有問題的;

(4)、 Finalize和Dispose共享相同的資源釋放策略,因此他們之間也是沒有沖突的。

 

 

 

 

2、IDisposable例子

 

 
C# 代碼   復制
namespace 資源回收
{    class Program    {        static void Main(string[] args)        {            //使用using對實現(xiàn)IDisposable的類了進行資源管理/*拿到一個對象的時候,首先判斷這個對象是否實現(xiàn)了IDisposable接口,如果實現(xiàn)了,最好就用using包裹住這個對象,保證這個對象用完之后被釋放掉,否則很可能出現(xiàn)資源泄露的問題*/            using (Telphone t1 = new Telphone())            {                t1.Open();                t1.Speak("hello");                t1.Bomb();                //t1.Dispose();//如果在這里調用了Dispose()方法釋放資源,那么在執(zhí)行t1.Open()方法就出錯,電話線已經(jīng)被剪斷了,無法再打電話了                t1.Open();                t1.Speak("I am back!");            }//代碼執(zhí)行到這里后,就會調用Dispose方法來進行資源回收            Console.ReadKey();        }    }    /// <summary>    /// Telphone類實現(xiàn)了IDisposable接口    /// </summary>    class Telphone : IDisposable    {        /// <summary>        /// 電話狀態(tài)        /// </summary>        private TelphoneState state;        /// <summary>        /// 打電話        /// </summary>        public void Open()        {            if (state == TelphoneState.Disposed)            {                throw new Exception("電話線已經(jīng)被剪斷,無法打開!");            }            state = TelphoneState.Open;            Console.WriteLine("拿起電話");        }        /// <summary>        /// 說話        /// </summary>        /// <param name="s">說話內容</param>        public void Speak(string s)        {            if (state != TelphoneState.Open)            {                throw new Exception("沒有連接");            }            Console.WriteLine(s);        }        /// <summary>        /// 掛掉電話        /// </summary>        public void Bomb()        {            state = TelphoneState.Close;            Console.WriteLine("掛掉電話");        }        IDisposable 成員    }    /// <summary>    /// 電話狀態(tài)枚舉    /// </summary>    enum TelphoneState    {        Open, Close, Disposed    }}

 

程序運行結果:

 

 

 

 

三、析構函數(shù)和IDisposable混合調用的例子

 

 
C# 代碼   復制
public class ResourceHolder : IDisposable
{      private bool isDispose = false;            // 顯示調用的Dispose方法  public void Dispose()       {           Dispose(true);          GC.SuppressFinalize(this);        }       // 實際的清除方法  protected virtual void Dispose(bool disposing)       {            if (!isDisposed)           {              if (disposing)            {                       // 這里執(zhí)行清除托管對象的操作.                  }                  // 這里執(zhí)行清除非托管對象的操作            }             isDisposed=true;      }      // 析構函數(shù)       ~ResourceHolder()      {            Dispose (false);      }}

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 河津市| 高碑店市| 皋兰县| 禹城市| 宜昌市| 循化| 周宁县| 越西县| 教育| 天祝| 延长县| 黄陵县| 成武县| 广昌县| 五峰| 海晏县| 郯城县| 喀喇| 孟津县| 江安县| 馆陶县| 东至县| 清河县| 巨野县| 巨野县| 祁门县| 衡南县| 台东县| 尉犁县| 荔波县| 泸定县| 自治县| 修文县| 东源县| 滨州市| 勐海县| 彭阳县| 新河县| 嘉善县| 兴国县| 靖西县|