程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 改善C#程序的建議5:引用類型賦值為null與加速垃圾回收

改善C#程序的建議5:引用類型賦值為null與加速垃圾回收

編輯:C#入門知識

在標准的Dispose模式中(見前一篇博客“html">C#中標准Dispose模式的實現”),提到了需要及時釋放資源,卻並沒有進一步細說讓引用等於null是否有必要。

有一些人認為等於null可以幫助垃圾回收機制早點發現並標識對象是垃圾。其他人則認為這沒有任何幫助。是否賦值為null的問題首先在方法的內部被人提起。現在,為了更好的闡述提出的問題,我們來撰寫一個Winform窗體應用程序。如下:

        private void button1_Click(object sender, EventArgs e)
{
Method1();
Method2();
}

private void button2_Click(object sender, EventArgs e)
{
GC.Collect();
}

private void Method1()
{
SimpleClass s = new SimpleClass("method1");
s = null;
//其它無關工作代碼(這條注釋源於回應回復的朋友的質疑)
}
private void Method2()
{
SimpleClass s = new SimpleClass("method2");
}
}

class SimpleClass
{
string m_text;

public SimpleClass(string text)
{
m_text = text;
}

~SimpleClass()
{
MessageBox.Show(string.Format("SimpleClass Disposed, tag:{0}", m_text));
}
}

先點擊按鈕1,再點擊按鈕2釋放,我們會發現:

q 方法Method2中的對象先被釋放,雖然它在Method1之後被調用;

q 方法Method2中的對象先被釋放,雖然它不像Method1那樣為對象引用賦值為null;

在CLR托管應用程序中,存在一個“根”的概念,類型的靜態字段、方法參數以及局部變量都可以作為“根”存在(值類型不能作為“根”,只有引用類型的指針才能作為“根”)。

上面的兩個方法中各自的局部變量,在代碼運行過程中會在內存中各自創建一個“根”.在一次垃圾回收中,垃圾回收器會沿著線程棧上行檢查“根”。檢查到方法內的“根”時,如果發現沒有任何一個地方引用了局部變量,則不管是否為變量賦值為null,都意味著該“根”已經被停止掉。然後垃圾回收器發現該根的引用為空,同時標記該根可被釋放,這也表示著Simple類型對象所占用的內存空間可被釋放。所以,在上面的這個例子中,為s指定為null絲毫沒有意義(方法的參數變量也是這種情況)。

更進一步的事實是,JIT編譯器是一個經過優化的編譯器,無論我們是否在方法內部為局部變量賦值為null,該語句都會被忽略掉

view sourceprint? s = null;

在我們將項目設置為Release模式下,上面的這行代碼將根本不會被編譯進運行時內。

正式由於上面這樣的分析,很多人認為為對象賦值為null完全沒有必要。但是,在另外一種情況下,卻要注意及時為變量賦值為null。那就是類型的靜態字段。為類型對象賦值為null,並不意味著同時為類型的靜態字段賦值為null:

        private void button1_Click(object sender, EventArgs e)
{
SimpleClass s = new SimpleClass("test");
}

private void button2_Click(object sender, EventArgs e)
{
GC.Collect();
}
}

class SimpleClass
{
static AnotherSimpleClass asc = new AnotherSimpleClass();
string m_text;

public SimpleClass(string text)
{
m_text = text;
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved