C#中的數據類型分爲值類型 (Value type) 和引用類型(reference type),程序員
值 類 型: 全部的值類型都集成自 System.ValueType 上,除非加聲明?不然不可爲null,保存在 堆棧(Stack,先進後出)上,常見的值類型有:整形、浮點型、bool、枚舉等。算法
引用類型:全部的引用類型都繼承自System.Object 上,引用類型保存在 託管堆(Head,先進先出)上,常見的類型有:數組、字符串、接口、委託、object等。數據庫
拆箱和裝箱:引用類型和值類型的相互轉換叫作拆裝箱操做。數組
拆箱:拆箱就是將一個引用型對象轉換成任意值型!好比:網絡
int i=0; System.Object obj=i; int j=(int)obj;
裝箱:裝箱就是隱式的將一個值型轉換爲引用型對象。好比:編輯器
int i=0; Syste.Object obj=i;
C#中和Java同樣是一種系統自動回收釋放資源的語言,在C#環境中經過 GC(Garbage Collect)進行系統資源回收,在數據基本類型中介紹到,C#數據類型分爲引用類型和值類型,ide
值類型保存在Stack上,隨着函數的執行做用域執行完畢而自動出棧,因此這一類型的資源不是GC所關心 對象。GC垃圾回收主要是是指保存在Heap上的資源。函數
.NET的GC機制有這樣兩個問題:
首先,GC並非能釋放全部的資源。它不能自動釋放非託管資源。
第二,GC並非實時性的,這將會形成系統性能上的瓶頸和不肯定性。
GC並非實時性的,這會形成系統性能上的瓶頸和不肯定性。因此有了IDisposable接口,IDisposable接口定義了Dispose方法,這個方法用來供程序員顯式調用以釋放非託管資源。使用using語句能夠簡化資源管理。
性能
上面介紹到,GC只釋放託管資源,那麼什麼是託管資源和費託管資源。優化
託管資源 : 託管資源指的是.NET能夠自動進行回收的資源,主要是指託管堆上分配的內存資源。託管資源的回收工做是不須要人工干預的,有.NET運行庫在合適調用垃圾回收器進行回收。
非託管資源:非託管資源指的是.NET不知道如何回收的資源,最多見的一類非託管資源是包裝操做系統資源的對象,例如文件,窗口,網絡鏈接,數據庫鏈接,畫刷,圖標 等。這類資源,
垃圾回收器在清理的時候會調用Object.Finalize()方法。默認狀況下,方法是空的,對於非託管對象,須要在此方法中編寫回收非託管資源的代碼,以便垃圾回收器正確回收資源。
總結:託管資源是釋放由GC來完成,釋放的時間吧不必定,通常是系統感受內存吃緊,會進行緊急回收資源。一個對象想成爲被回收,首先須要成爲垃圾,GC是經過判斷對象及其子對象有沒有指向有效的引用,
若是沒有GC就認爲它是垃圾。垃圾回收機制經過必定的算法獲得哪些沒有被被引用、或者再也不調用的資源,當這些垃圾達到必定的數量時,回啓動垃圾回收機制,GC回收其實是調用了析構函數。
垃圾回收機制意味着你不須要擔憂處理再也不須要的對象了。我們關心的主要是非託管資源的釋放。
垃圾回收時對象一共有三代 :0,1,2。每一代都有本身的內存預算,空間不足的時候會調用垃圾回收。爲了提升性能都是按代回收,第0代超預算以後就回收第0代的對象,而存活下來的對象就提高爲第1代,
依次類推,而每每通過屢次0代的垃圾回收才能回收一次第1代。
GC進行垃圾回收是系統決定的,下面是進行強制回收的執行代碼(非特殊狀況下不要使用此方法,會影響系統效率,削弱垃圾回收器中優化引擎的做用,而垃圾回收器能夠肯定運行垃圾回收的最佳時間)
//對全部代進行垃圾回收。 GC.Collect(); //對指定的代進行垃圾回收。 GC.Collect(int generation); //強制在 System.GCCollectionMode 值所指定的時間對零代到指定代進行垃圾回收。 GC.Collect(int generation, GCCollectionMode mode);
在定義一個類時,可使用兩種不一樣的機制類釋放非託管資源,這兩週機制有時候一般放在一塊兒使用
一、聲明析構函數(終結器)嗎,做爲類的成員
構造函數能夠在建立對象實例的時候執行某些操做,析構函數正好相反是資源建立之後被系統回收的時候執行的操做,垃圾回收器在回收對象以前會調用析構函數,因此在函數代碼塊中能夠寫釋放非
託管資源的代碼。析構函數沒有返回值,沒有參數,沒有修飾符。
public class AA { ~AA() { //析構函數語法 } }
析構函數會被編輯器翻譯成下面的代碼:
protected override void Finalize() { try { // Cleanup statements... } finally { base.Finalize(); } }
最終析構函數會被翻譯成上面的代碼塊,重寫基類的Finalize()方法,而後最終調用 Base.Finalize()方法。
注意!大量的使用析構函數會影響效率!帶有析構函數的對象會被系統執行兩次纔會被釋放掉。GC執行釋放資源時,沒有析構函數的資源會被直接釋放掉,假如目標對象有析構函數,會被先放進一個叫作「終結隊列」的
項中去,而後系統調用另外一個高優先級線程來執行 Finalize()方法,GC繼續回收其它對象。等方法執行完之後會將對象從終結隊列中清除出去,此時對象纔是真正意義上的垃圾。等GC執行資源回收的時候,纔回釋放掉終結隊列裏面的對象。
總結:
綜上所述,建議是不要實現其析構函數,這將大大下降程序的性能。
二、在類中實現 System.IDisposable 接口
實現IDisposable接口來顯示釋放系統資源
class Test:IDisposable { #region IDisposable Support private bool disposedValue = false; // 要檢測冗餘調用 protected virtual void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { // TODO: 釋放託管狀態(託管對象)。 } // TODO: 釋放未託管的資源(未託管的對象)並在如下內容中替代終結器。 // TODO: 將大型字段設置爲 null。 disposedValue = true; } } // TODO: 僅當以上 Dispose(bool disposing) 擁有用於釋放未託管資源的代碼時才替代終結器。 ~Test() { // 請勿更改此代碼。將清理代碼放入以上 Dispose(bool disposing) 中。 Dispose(false); } // 添加此代碼以正確實現可處置模式。 public void Dispose() { // 請勿更改此代碼。將清理代碼放入以上 Dispose(bool disposing) 中。 Dispose(true); // TODO: 若是在以上內容中替代了終結器,則取消註釋如下行。 // GC.SuppressFinalize(this); } #endregion }
① 當咱們顯示調用Dispose()方法之後,會執行釋放費託管資源的操做,而後disposedValue會爲Flase,因此咱們屢次調用也沒有關係。Dispose()調用執行完之後,執行 GC.SuppressFinalize(this)(告訴GC再也不執行終結器操做) 代碼
② 若是咱們不調用 Diapose()方法,系統會調用使用終結器操做,最後也是釋放非託管資源。
總結:
當釋放非託管資源時咱們應該顯式的去實現Dipose()方法或者Close()方法,可是萬一咱們忘記顯式去調用方法,此時還有一條退路,CLR會自動調用Finalize()方法,
很顯然調用Finalize()方法會大大下降程序的性能,不要緊,上述釋放模式關鍵的一點是經過手動釋放調用Dispose()方法能夠阻止Finalize()方法的調用,換言之,上述經過手動釋放既釋放了非託管資源又加快了程序運行的速度,毫無疑問,這是一種完美的解決方案。
一、Finalize是系統決定執行的,咱們沒法干涉。Dispose是能夠咱們調用來釋放的。
二、Finalize只能釋放費託管資源,Dispose既能夠釋放託管資源也能夠釋放非託管資源。