三、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方法,這樣就形成了一個在堆上永遠不會死去的對象,像鳳凰涅槃一樣每次死的時候都可以復生。
託管資源:
Net中的所有類型都是(直接或間接)從System.Object類型派生的。
CTS中的類型被分成兩大類——引用類型(reference type,又叫託管類型[managed type]),分配在內存堆上,值類型(value type)。值類型分配在堆棧上。如圖
值類型在棧裏,先進後出,值類型變量的生命有先後順序,這個確保了值類型變量在推出作用域以前會釋放資源。比引用類型更簡單和高效。堆棧是從高地址往低地址分配內存。
引用類型分配在託管堆(Managed Heap)上,聲明一個變量在棧上保存,當使用new創建對象時,會把對象的地址存儲在這個變量裏。託管堆相反,從低地址往高地址分配內存,如圖
.net中超過80%的資源都是託管資源。
非託管資源:
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();
}
}
}
}