淺談C#託管程式中的資源釋放問題

來源:互聯網
上載者:User
正在裝載資料……

 用了.Net工具來寫程式的人,不難發現它有個好處,就是使用的記憶體不用釋放,尤其在使用C#或者VB.Net來寫程式,因為程式所佔用的記憶體都是受系統託管的,因此記憶體的釋放不需要程式員去操心。 很多人從C語言或者C++等等語言轉型過來,對於這一點往往很不適應,例如定義一個數組或者去new一個對象的時候,都習慣在使用完畢後用Delete語句去釋放它,然而在C#中沒有提供類似的語句來進行同樣的操作。 那麼有人就問,是不是.Net不用去釋放記憶體,或者問假如要去顯示釋放一個對象,該如何去做。  那麼我要明確告訴一點的就是,在C#中記憶體的回收是GC去做的,我們在程式中最多隻是標記當前對象不再被引用就行了(而GC何時去回收是不確定的,因為回收記憶體是比較費時費力的,被觸發的可能性在於記憶體緊張或者顯示調用GC.Collect)。明白這一點後,那麼我們在寫程式的時候,當所定義的類型使用了比較大的記憶體資源或者使用了會引起操作衝突的資源,例如:各種連線物件,各種Stream對象,各種與圖有關的對象,各種互斥對象等等,需要提供介面來進行關閉和標記,從而在GC回收的時候能提高效率。 .Net提供了三種方法,也是最常見的三種,大致如下:1. 解構函式;2. 繼承IDisposable介面,實現Dispose方法;3. 提供Close方法。 對於解構函式來說,長時間使用C#的人們,都會對它產生淡忘。或者說用C#編寫一個類的時候,很少編寫類的解構函式。而對於C#的解構函式來說,基本上延用了原來C++中的意思。 但是在C#中不能像C++那樣顯示去刪除一個對象,那麼對象的解構函式調用是當GC檢測到此對象不再被引用時,才進行刪除,此時才會被調用。而對於GC何時去檢測和收集是不確定的,因此對象的解構函式調用時機也是不確定的。這裡也暗藏了一個道理,就是在解構函式中去做一些資源的關閉和標記就不是很合理了,因為所佔有的資源無法迅速地進行關閉或者標記為無用。 解構函式不能顯示調用,而對於後兩種方法來說,都需要進行顯示調用才能被執行。 Close與Dispose這兩種方法的區別在於,調用完了對象的Close方法後,此對象有可能被重新進行使用;而Dispose方法來說,此對象所佔有的資源需要被標記為無用了,也就是此對象要被銷毀,不能再被使用。例如常見.Net類庫中的SqlConnection這個類,當調用完Close方法後,可以通過Open重新開啟一個資料庫連接,當徹底不用這個對象了就可以調用Dispose方法來標記此對象無用,等待GC回收。明白了這兩種方法的意思後,大家在往自己的類中添加的介面時候,不要歪曲了這兩者意思。 接下來說說這三個函數的調用時機,我用幾個實驗結果來進行說明,可能會使大家的印象更深。首先是這三種方法的實現,大致如下:    ///<summary>    /// The class to show three disposal function    ///</summary>    public class DisposeClass:IDisposable    {        public void Close()        {            Debug.WriteLine( "Close called!" );        }         ~DisposeClass()        {            Debug.WriteLine( "Destructor called!" );        }         #region IDisposable Members         public void Dispose()        {            // TODO: Add DisposeClass.Dispose implementation            Debug.WriteLine( "Dispose called!" );        }         #endregion    } 對於Close來說不屬於真正意義上的釋放,除了注意它需要顯示被調用外,我在此對它不多說了。而對於解構函式而言,不是在對象離開範圍後立刻被執行,只有在關閉進程或者調用GC.Collect方法的時候才被調用,參看如下的代碼運行結果。        private void Create()        {            DisposeClass myClass = new DisposeClass();        }         private void CallGC()        {            GC.Collect();        }         // Show destructor        Create();        Debug.WriteLine( "After created!" );        CallGC(); 啟動並執行結果為: After created! Destructor called! 顯然在出了Create函數外,myClass對象的解構函式沒有被立刻調用,而是等顯示調用GC.Collect才被調用。 對於Dispose來說,也需要顯示的調用,但是對於繼承了IDisposable的類型對象可以使用using這個關鍵字,這樣對象的Dispose方法在出了using範圍後會被自動調用。例如:    using( DisposeClass myClass = new DisposeClass() )    {        //other operation here    } 如上啟動並執行結果如下: Dispose called! 那麼對於如上DisposeClass類型的Dispose實現來說,事實上並沒有達到標記記憶體無用的目的,也就是說對象的解構函式還會被調用。 那 麼有人就問,既然Dispose方法中去為了顯示標記此對象已經不再引用,那麼調用對象的解構函式已經沒有什麼意義,是否能在Dispose中增加處理, 來避免解構函式的調用。答案是有的,就是需要在Dispose方法中,加上調用GC.SupdivssFinalize(this )的語句。那麼改寫後的DisposeClass如下:    ///<summary>    /// The class to show three disposal function    ///</summary>    public class DisposeClass:IDisposable    {        public void Close()        {            Debug.WriteLine( "Close called!" );        }         ~DisposeClass()        {            Debug.WriteLine( "Destructor called!" );        }         #region IDisposable Members         public void Dispose()        {            // TODO: Add DisposeClass.Dispose implementation            Debug.WriteLine( "Dispose called!" );            GC.SupdivssFinalize( this );        }         #endregion    } 通過如下的代碼進行測試。        private void Run()        {            using( DisposeClass myClass = new DisposeClass() )            {                //other operation here            }        }         private void CallGC()        {            GC.Collect();        }         // Show destructor        Run();        Debug.WriteLine( "After Run!" );        CallGC(); 啟動並執行結果如下: Dispose called! After Run! 顯然對象的解構函式沒有被調用。通過如上的實驗以及文字說明,大家會得到如下的一個對比表格。

  解構函式 Dispose方法 Close方法
意義 銷毀對象 銷毀對象 關閉對象資源
調用方式 不能被顯示調用,在GC回收是被調用 需要顯示調用或者通過using語句 需要顯示調用
調用時機 不確定 確定,在顯示調用或者離開using程式塊 確定,在顯示調用時
 那麼在定義一個類型的時候,是否一定要給出這三個函數地實現呢。  我的建議大致如下。 1.  一般不要提供解構函式,因為它不能及時地被執行; 2.  對於Dispose 和Close 方法來說,需要看所定義的類型所使用的資源(參看前面所說),而決定是否去定義這兩個函數; 3.  在實現Dispose 方法的時候,一定要加上“ GC.SupdivssFinalize( this ) ”語句。 C#程式所使用的記憶體是受託管的,但不意味著濫用,好地編程習慣有利於提高代碼的品質以及程式的運行效率。

本文來源:http://blog.csdn.net/kong1122/archive/2007/08/02/1722685.aspx

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.