[.net 面向對象程序設計進階] (8) 託管與非託管

本節導讀:雖然在.NET編程過程當中,絕大多數內存垃圾回收由CLR(公共語言運行時)自動回收,但也有不少須要咱們編碼回收。掌握託管與非託管的基本知識,能夠有效避免某些狀況下致使的程序異常。html

1.什麼是託管與非託管?數據庫

託管資源:通常是指被CLR(公共語言運行時)控制的內存資源,這些資源由CLR來管理。能夠認爲是.net 類庫中的資源。編程

非託管資源:不受CLR控制和管理的資源c#

對於託管資源,GC負責垃圾回收。對於非託管資源,GC能夠跟蹤非託管資源的生存期,可是不知道如何釋放它,這時候就要人工進行釋放。安全

2.哪些資源是非託管的?網絡

整體來講就是 不受CLR控制和管理的資源函數

包括:好比文件流、圖像圖形類、數據庫的鏈接,網絡鏈接,系統的窗口句柄,打印機資源等,這類資源通常不存在堆上。能夠認爲操做系統資源的一組API性能

原則:若是咱們的類使用的非託管資源,如數據庫鏈接、文件句柄,這些資源需作到:使用後馬上釋放。this

3.如何釋放非託管資源?編碼

.NET對於釋放資源,標準作法以下:

1)繼承IDisposable接口;

2)實現Dispose()方法在其中釋放託管資源和非託管資源,並將對象自己從垃圾回收器中移除(垃圾回收器不在回收此資源);

3 實現類析構函數在其中釋放非託管資源。

 對於Dispose()方法的幾個參數說明:

A. 參數爲true表示釋放全部資源,只能由使用者調用

 參數爲false表示釋放非託管資源,只能由垃圾回收器自動調用

C. 若是子類有本身的非託管資源,能夠重載這個函數,添加本身的非託管資源的釋放

D.可是要記住,重載此函數必須保證調用基類的版本,以保證基類的資源正常釋放

4.舉例說明資源釋放

4.1 數據庫鏈接釋放

(1)錯誤作法:

   SqlConnection conn = new SqlConnection();

    //do something;

conn.Dispose();

此段代碼,若是出現異常conn.Dispose()未能及時執行,會致使沒有及時關閉鏈接。

(2)正確作法:       

SqlConnection conn = new SqlConnection();
try
{
    //do something;
}
finally
{
    conn.Dispose();
}

  對於以上代碼,咱們還能夠簡化代碼量,c#使用using簡化輸入,編譯器自動翻譯成 try...finally,改成下面寫法

(3)改進作法: 

using(SqlConnection conn = new SqlConnection())
{
      //do something;
}

4.2 資源回收綜合示例 

public class BaseResource : IDisposable
    {
        private IntPtr handle; // 句柄,屬於非託管資源
        private System.ComponentModel.Component comp; // 組件,託管資源
        private bool isDisposed = false; // 是否已釋放資源的標誌

        //實現接口方法
        //由類的使用者,在外部顯示調用,釋放類資源
        public void Dispose()
        {
            Dispose(true);// 釋放託管和非託管資源

            //將對象從垃圾回收器鏈表中移除,
            // 從而在垃圾回收器工做時,只釋放託管資源,而不執行此對象的析構函數
            GC.SuppressFinalize(this);
        }

        //由垃圾回收器調用,釋放非託管資源
        ~BaseResource()
        {
            Dispose(false);// 釋放非託管資源
        }

        //參數爲true表示釋放全部資源,只能由使用者調用
        //參數爲false表示釋放非託管資源,只能由垃圾回收器自動調用
        //若是子類有本身的非託管資源,能夠重載這個函數,添加本身的非託管資源的釋放
        //可是要記住,重載此函數必須保證調用基類的版本,以保證基類的資源正常釋放
        protected virtual void Dispose(bool disposing)
        {
            if (!this.isDisposed)// 若是資源未釋放 這個判斷主要用了防止對象被屢次釋放
            {
                if (disposing)
                {
                    comp.Dispose();// 釋放託管資源
                }               
            }
            this.isDisposed = true; // 標識此對象已釋放
        }
    }

5.對於釋放資源注意的幾點

A. 顯示調用Dispose()方法,能夠及時的釋放資源,同時經過移除Finalize()方法的執行,提升了性能;

B. 若是沒有顯式調用Dispose()方法,垃圾回收器也能夠經過析構函數來釋放非託管資源,垃圾回收器自己就具備回收託管資源的功能,從而保證資源的正常釋放,只不過由垃圾回收器回收會致使非託管資源的未及時釋放的浪費。

C. .NET中應該儘量的少用析構函數釋放資源。在沒有析構函數的對象在垃圾處理器一次處理中從內存刪除,但有析構函數的對象,須要兩次,第一次調用析構函數,第二次刪除對象。並且在析構函數中包含大量的釋放資源代碼,會下降垃圾回收器的工做效率,影響性能。

D. 對於包含非託管資源的對象,最好及時的調用Dispose()方法來回收資源,而不是依賴垃圾回收器

E. 析構函數只能由垃圾回收器調用。

F. Despose()方法只能由類的使用者調用。

G. .NET中,凡是繼承了IDisposable接口的類,均可以使用using語句,從而在超出做用域後,讓系統自動調用Dispose()方法。
H. 一個資源安全的類,都實現了IDisposable接口和析構函數。提供手動釋放資源和系統自動釋放資源的雙保險。

6. 關於Finalize和Dispose

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

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

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

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

7. 要點:

本節內容比較簡單,主要了解了.NET託管和非託管兩種資源,絕大多部資源由CLR(公共語言運行時)自動釋放,稱爲託管代碼;還有一部分資源須要人工釋放,稱爲非託管代碼。掌控非託管代碼的幾種內存釋放方法,能夠以效的避免程序產生異常,合理釋放內存,有利於程序穩定和流暢。

==============================================================================================  

 返回目錄

 <若是對你有幫助,記得點一下推薦哦,若有

有不明白或錯誤之處,請多交流>  

<對本系列文章閱讀有困難的朋友,請先看《.net 面向對象編程基礎》>

<轉載聲明:技術須要共享精神,歡迎轉載本博客中的文章,但請註明版權及URL>

.NET 技術交流羣:467189533    .NET 程序設計

==============================================================================================   

相關文章
相關標籤/搜索