標籤:不能 正是 靜態變數 佔用 線程 引用 使用 變數 col
建議53:必要時應將不再使用的對象引用賦值為null
在CLR託管的應用程式中,存在一個“根”的概念,類型的靜態欄位、方法參數、以及局部變數都可以作為“根”的存在(實值型別不能作為“根”,只有參考型別的指標才能作為“根”)。
局部變數在代碼運行過程中會在記憶體中建立一個“根”。在一次記憶體回收中,記憶體回收行程會沿著線程棧上行檢查“根”(線程棧檢查完畢後,還會檢查所有的參考型別對象的靜態欄位的根集合)。當檢測到方法內的“根”時,如果發現沒有任何一個地方引用了局部變數,則不管是否已經顯式將其賦值為null,都意味著該“根”已經被停止。然後,記憶體回收行程會發現該根的引用為空白,同時標記該根可被釋放,這也代表著類型對象所佔用的記憶體空間可以被釋放。所以為局部變數指定為null絲毫沒有意義,方法的參數變數也是這種情況。
JIT編譯器是一個最佳化過的編譯器,無論我們是否在方法內將局部變數賦值為null,如下面語句:
SampleClass c1=new SampleClass(); c1 = null;
中c1 = null;這句都會被忽略。如果我們將項目設定為Release模式,這句話根本不會被編譯進運行時內。
正是由於以上分析,很多人會認為將對象賦值為null完全沒有必要。但是,在另一種情況下,卻要注意及時地將變數賦值為null,那就是類型的靜態欄位。將類型對象賦值為null,並不意味著同時將類型的靜態欄位賦值為null。當類型對象被回收時,類型的靜態欄位卻沒有被回收。
之所以靜態欄位不被釋放(同時賦值為null語句也不會像局部變數那樣被運行時編譯器最佳化),是因為靜態欄位一旦被建立,該“根”就一直存在。所以,記憶體回收行程始終不會認為它是一個垃圾。非靜態欄位則不存在這樣一個問題。
在實際工作中,一旦我們感覺到自己的靜態參考型別參數佔用的記憶體空間比較大,並且用完後不會再使用,可以立即將其賦值為null。這也許並不必要,但這是一個好習慣。試想,如果一個系統中那些時不時在類中出現的靜態變數,它們那樣靜靜地待在記憶體中,一旦被建立,就永遠不會離開。所以,盡量少用靜態變數。
轉自:《編寫高品質代碼改善C#程式的157個建議》陸敏技
【轉】編寫高品質代碼改善C#程式的157個建議——建議53:必要時應將不再使用的對象引用賦值為null