C#基礎知識回顧:1.由WeakReference想到對象的建立與銷燬

.Net Framework中,把資源分爲託管資源和非託管資源兩大類,數據庫

託管資源指能夠經過.Net Frame垃圾回收器進行回收的資源,主要是指分配在託管堆上你的內存資源,這類資源的回收是不須要人工干預,.Net Framework的垃圾回收器會在合適的時刻進行回收,程序也能夠主動調用GC.Collect()強制執行垃圾回收可是不建議編程

非託管資源則是指不能被.Net Framework垃圾回收器回收的資源,主要包括如下幾類:文件讀寫、窗口操做、網絡鏈接、數據庫鏈接、GDI畫刷、圖標等。針對這類資源,垃圾回收器可以跟蹤其生存期,但不瞭解具體如何清理這些資源。針對這類資源,垃圾回收器在清理的時候回調用Object.Finalize()方法,該方法是虛方法,非託管對象須要重寫方法來實現資源回收。網絡

託管對象是不能重載Object.Finalize()方法,編譯器會自動根據析構函數生成對應的Object.Finalize()方法,所以,當託管對象中使用到非託管資源時,須要在析構函數中釋放該資料。app

析構函數的定義以下(在方法名稱爲類名稱前加了一個「~」):函數

    public class TestA
    {
        public string Name = "TestA";
        ~TestA()
        {
            Console.WriteLine("Dispose TestA");
        }
    }

 

因爲析構函數是有垃圾回收器主動調用的,所以,調用該方法前,類包含的託管對象可能已經被主動回收了,此時再進行釋放操做,可能會形成異常,所以,不建議在析構函數中釋放託管資源。性能

垃圾回收器的操做時機是.NetFramework本身所決定的,它會在系統內存的佔用和系統系統之間做一個平衡來決定什麼時候出發,所以,對於非託管資源,這類資源屬於寶貴資源,必須及時地釋放掉,不能有垃圾回收器來決定什麼時候釋放。spa

.Net Framework中爲回收資源,而定義了一個接口,IDisposable定義爲:code

 1     //
 2     // 摘要:
 3     //     Defines a method to release allocated resources.
 4     [ComVisible(true)]
 5     public interface IDisposable
 6     {
 7         //
 8         // 摘要:
 9         //     Performs application-defined tasks associated with freeing, releasing, or resetting
10         //     unmanaged resources.
11         void Dispose();
12     }

任何包括非託管資源的類都須要繼承此接口,並在接口方法中實現對託管資源和非託管資源的釋放操做,同時在析構函數中實現對非託管資源的釋放。orm

這麼實現的好處就是:代碼中顯示調用Dispose()時,可以主動地釋放資源(託管和非託管),垃圾回收器就會移除該對象不會執行回收操做(即再也不執行Finalize()方法),從而提升了性能。而若是沒有顯示調用Dispose(),垃圾回收器也會在適當的時機調用Finalize()方法來釋放非託管資源。對象

C#語言中using關鍵字做爲語法糖出現,將非託管資源的使用包含在using()中使用,執行完成後會主動調用Dispose方法來釋放資源。

基於性能考慮,應該下降使用析構函數來釋放資源的使用頻率,所以,沒有析構函數的對象在垃圾處理器中直接刪除,而包括析構函數的對象,則須要先執行析構函數,而後刪除對象,增長了一次操做,會下降垃圾回收器的工做效率,從而影響性能。所以,對於非託管對象的釋放,應該實現IDispose接口來回收資源,而不依賴垃圾回收器。

當前類使用new關鍵字建立了另外一個類的實例時,當前類對新建的類實例的引用稱爲強引用,當新建類實例沒有釋放時,垃圾回收器則沒法回收這個對象。只有將該引用釋放的時候,垃圾回收器纔會回收該對象。

1 TestA a = new TestA();
2 a = null;
3 GC.Collect();
4 //當把變量a置爲null,主動執行垃圾回收後就會回收該對象。

編程過程,咱們會遇到這樣的場景,持有一個對象實例的引用,這個實例比較龐大且建立成本不是過高,可是使用頻率比較低。該狀況下,能夠使用WeakReference對這個實例進行包裝,當須要使用當對象時,先調用WeakReference.IsAlive是否等於true或者Target不等於null,判斷該對象實例是否存在,若存在則調用其Target並強制轉換後使用,若不存在,則須要從新建立一個新的實例來使用。使用WeakReference包括的對象實例,垃圾回收器會釋放該實例,回收其內存空間。所用,使用前必須判斷其是否仍然存在。

相關文章
相關標籤/搜索