.Net Framework中,把資源分為托管資源和非托管資源兩大類, 托管資源指可以通過.Net Frame垃圾回收器進行回收的資源,主要是指分配在托管堆上你的記憶體資源,這類資源的回收是不需要人工干預,.Net Framework的垃圾回收器會在合適的時刻進行回收,程式也可以主動調用GC.Coll ...
.Net Framework中,把資源分為托管資源和非托管資源兩大類,
托管資源指可以通過.Net Frame垃圾回收器進行回收的資源,主要是指分配在托管堆上你的記憶體資源,這類資源的回收是不需要人工干預,.Net Framework的垃圾回收器會在合適的時刻進行回收,程式也可以主動調用GC.Collect()強制執行垃圾回收(但是不建議)。
非托管資源則是指不能被.Net Framework垃圾回收器回收的資源,主要包括以下幾類:文件讀寫、視窗操作、網路連接、資料庫連接、GDI畫刷、圖標等。針對這類資源,垃圾回收器能夠跟蹤其生存期,但不瞭解具體如何清理這些資源。針對這類資源,垃圾回收器在清理的時候回調用Object.Finalize()方法,該方法是虛方法,非托管對象需要重寫方法來實現資源回收。
托管對象是不能重載Object.Finalize()方法,編譯器會自動根據析構函數生成對應的Object.Finalize()方法,因此,當托管對象中使用到非托管資源時,需要在析構函數中釋放該資料。
析構函數的定義如下(在方法名稱為類名稱前加了一個“~”):
public class TestA { public string Name = "TestA"; ~TestA() { Console.WriteLine("Dispose TestA"); } }
由於析構函數是有垃圾回收器主動調用的,因此,調用該方法前,類包含的托管對象可能已經被主動回收了,此時再進行釋放操作,可能會造成異常,因此,不建議在析構函數中釋放托管資源。
垃圾回收器的操作時機是.NetFramework自己所決定的,它會在系統記憶體的占用和系統系統之間作一個平衡來決定何時出發,因此,對於非托管資源,這類資源屬於寶貴資源,必須及時地釋放掉,不能有垃圾回收器來決定何時釋放。
.Net Framework中為回收資源,而定義了一個介面,IDisposable定義為:
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 }
任何包括非托管資源的類都需要繼承此介面,併在介面方法中實現對托管資源和非托管資源的釋放操作,同時在析構函數中實現對非托管資源的釋放。
這麼實現的好處就是:代碼中顯示調用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包括的對象實例,垃圾回收器會釋放該實例,回收其記憶體空間。所用,使用前必須判斷其是否仍然存在。