將值設置爲null通常無關緊要。這是非常有用的。偶爾有害。
讓我們首先考慮最簡單的情況:
private void DoStuff()
{
var newWin = new WinWorkers_AddWorker();
newWin.WindowState = this.WindowState;
newWin.Show();
int irrelevant = 42;
this.whoCares = irrelevant * 7;
int notRelevantEither = irrelevant + 1;
this.stillDontCare = notRelevantEither * irrelevant;
}
這裏newWin
只存在於這種方法;它會在其中創建,並且不會通過返回或分配給具有更廣範圍的成員來留下方法的範圍。
問問很多人,當newWin
得到垃圾收集,他們會告訴你,它會發生在this.stillDontCare
行後,因爲那時newWin
超出範圍。因此,我們可以通過在其最後一次使用後指定newWin = null
來輕微獲勝,但其可能忽略不計。
從概念上講,這是真的,因爲我們可以添加處理newWin
直到那一點的代碼,並且我們可以使用newWin
。
實際上,newWin
很有可能在.Show()
之後成爲收集資格。雖然從理論上講它在此後的範圍內,但它並未實際使用,編譯器也知道這一點。 (從現在開始,「編譯器」就是指產生實際運行代碼的整個過程,結合IL編譯器和抖動)。由於使用newWin
本身的內存(即堆棧上的引用,而不是對象)不再使用的編譯器可以使用的內存爲irrelevant
或別的東西。如果沒有實時參考,則該對象有資格收集。事實上,如果調用對象的最後幾個方法實際上並不使用指針(無論是直接使用還是使用成員字段),那麼甚至可以在調用這些方法之前收集對象,因爲它們不會實際上是利用這個對象。如果你有一個方法的指針從未被使用過(直接或間接),那麼它可能永遠不會被創建!現在,考慮到這一點,我們可以看到,如果我們在變量失效之前給變量賦予null值,那麼它看起來確實不會產生輕微的微不足道的差異,範圍。
事實上,賦值甚至可能使得變得合格需要更長的時間,因爲如果編譯器無法看到變量的使用不會影響對象(不太可能,但也許可能如果存在使得分析更復雜的塊,則可能會發生),那麼它甚至可能延遲該對象被認爲合格的點。這又可能忽略不計,但它在那裏。
到目前爲止那麼簡單;如果我們保持良好的狀態,好的事情就會發生,而且保持良好狀態很容易
然而,可以用於參考從被設置爲空值受益。試想一下:
public class SomeClass
{
private WorkerThing _newWin;
private void DoStuff()
{
_newWin = new WinWorkers_AddWorker();
_newWin.WindowState = this.WindowState;
_newWin.Show();
}
}
考慮在這裏,那DoStuff()
後這段時間被稱爲,_newWin
存儲在一個成員變量。在SomeClass
的範例超出範圍之前,它不會超出範圍。什麼時候會發生?
好了,我不能回答這個問題,但有時答案是很重要的。如果SomeClass
本身也是短命的,那麼誰在乎。它很快就會掉到範圍之外,帶着它_newWin
。然而,如果我們分配了_newWin = null
,那麼該對象將立即有資格收集。
現在,這一些重要的注意事項:
- 首先,沒有充分的理由
_newWin
是一個成員變量。如果上面的例子是完整的代碼,我們將遷回它是本地DoStuff()
並獲得不僅在這個效率的方式,但多,我們的正確性的機會,因爲我們不能做一些愚蠢到_newWin
更重要來自另一位成員。
- 如果我們持有到的東西在一個成員變量,它可能是一個很好的理由。這個好理由將會超越對儘可能快地清理變量的狂熱。
- 無論如何,大多數物體本身並不佔用那麼多的記憶。這裏或那裏的成員變量不會受到傷害。
因此,將null分配給成員變量的主要原因很簡單,因爲null已成爲最合適的值。爲不再使用的成員分配空值通常不是儘快釋放其內存,而是因爲它不再適合使用,而且這變得不可能 - 並且清晰地向您的代碼中的其他代碼發出信號 - 當它一片空白。
如果參考物壽命長於方法(且因此放置在一個成員變量)和相當壽命短於包含對象和消耗非常大量的存儲器,那麼它只是對可能分配null將開始有意義。在發生這種組合的極其罕見的情況下,我們可能希望將它分配給null以指示它不再存在以供班級使用,所以我們仍不會指定空值,其目的是釋放它給了GC。這只是可能的,但真的「沒有」。
注意計數並不是它收集的真實方式。 Afaik它是標記和掃描或類似的。 – Dykam 2010-10-15 14:35:41
@Dykam是正確的,它是標記和掃描。就此而言,它可以在超出範圍之前收集。應該添加詳細的答案。 – 2010-10-15 15:47:03
Mono也沒有引用計數。 – 2010-10-15 16:38:40