步步爲營 C# 技術漫談 4、垃圾回收機制(GC) 中

 

3、Finalization Queue和Freachable Queue程序員

這兩個隊列和.net對象所提供的Finalize方法有關。這兩個隊列並不用於存儲真正的對象,而是存儲一組指向對象的指針。當程序中使用了new操做符在Managed Heap上分配空間時,GC會對其進行分析,若是該對象含有Finalize方法則在Finalization Queue中添加一個指向該對象的指針。在GC被啓動之後,通過Mark階段分辨出哪些是垃圾。再在垃圾中搜索,若是發現垃圾中有被Finalization Queue中的指針所指向的對象,則將這個對象從垃圾中分離出來,並將指向它的指針移動到Freachable Queue中。這個過程被稱爲是對象的復生(Resurrection),原本死去的對象就這樣被救活了。爲何要救活它呢?由於這個對象的Finalize方法尚未被執行,因此不能讓它死去。Freachable Queue平時不作什麼事,可是一旦裏面被添加了指針以後,它就會去觸發所指對象的Finalize方法執行,以後將這個指針從隊列中剔除,這是對象就能夠安靜的死去了。.net framework的System.GC類提供了控制Finalize的兩個方法,ReRegisterForFinalize和SuppressFinalize。前者是請求系統完成對象的Finalize方法,後者是請求系統不要完成對象的Finalize方法。ReRegisterForFinalize方法其實就是將指向對象的指針從新添加到Finalization Queue中。這就出現了一個頗有趣的現象,由於在Finalization Queue中的對象能夠復生,若是在對象的Finalize方法中調用ReRegisterForFinalize方法,這樣就造成了一個在堆上永遠不會死去的對象,像鳳凰涅槃同樣每次死的時候均可以復生。數據庫

 

託管資源:ide

Net中的全部類型都是(直接或間接)從System.Object類型派生的。性能

CTS中的類型被分紅兩大類——引用類型(reference type,又叫託管類型[managed type]),分配在內存堆上,值類型(value type)。值類型分配在堆棧上。如圖spa

alt

     值類型在棧裏,先進後出,值類型變量的生命有前後順序,這個確保了值類型變量在推出做用域之前會釋放資源。比引用類型更簡單和高效。堆棧是從高地址往低地址分配內存。.net

     引用類型分配在託管堆(Managed Heap)上,聲明一個變量在棧上保存,當使用new建立對象時,會把對象的地址存儲在這個變量裏。託管堆相反,從低地址往高地址分配內存,如圖指針

alt

.net中超過80%的資源都是託管資源。code

 

非託管資源:對象

ApplicationContext,Brush,Component,ComponentDesigner,Container,Context,Cursor,FileStream,Font,Icon,Image,Matrix,Object,OdbcDataReader,OleDBDataReader,Pen,Regex,Socket,StreamWriter,Timer,Tooltip ,文件句柄,GDI資源,數據庫鏈接等等資源。可能在使用的時候不少都沒有注意到!接口

 

.NET的GC機制有這樣兩個問題:

首先,GC並非能釋放全部的資源。它不能自動釋放非託管資源。

第二,GC並非實時性的,這將會形成系統性能上的瓶頸和不肯定性。

GC並非實時性的,這會形成系統性能上的瓶頸和不肯定性。因此有了IDisposable接口,IDisposable接口定義了Dispose方法,這個方法用來供程序員顯式調用以釋放非託管資源。使用using 語句能夠簡化資源管理。

示例

/// <summary>
/// 執行SQL語句,返回影響的記錄數
/// </summary>
/// <param name="SQLString">SQL語句</param>
/// <returns>影響的記錄數</returns>
public  static  int  ExecuteSql( string  SQLString)
{
     using  (SqlConnection connection = new  SqlConnection(connectionString))
     {
         using  (SqlCommand cmd = new  SqlCommand(SQLString, connection))
         {
             try
             {
                 connection.Open();
                 int  rows = cmd.ExecuteNonQuery();
                 return  rows;
             }
             catch  (System.Data.SqlClient.SqlException e)
             {
                 connection.Close();
                 throw  e;
             }
             finally
             {
                 cmd.Dispose();
                 connection.Close();
             }
         }
     }
}
相關文章
相關標籤/搜索