2010-10-15 68 views
4

在我的WPF應用程序,我在下面的方式調用新的窗口:內存消費代碼優化,垃圾收集理論

_newWin = new WinWorkers_AddWorker(); 
_newWin.WindowState = this.WindowState; 
_newWin.Show(); 

_newWinprivate Window object

我的問題是我應該給_newWin分配一個空值,我呼叫_newWin.Show()

這是否會減少內存消耗,因爲垃圾收集器/析構函數將在早期清理空值對象?

謝謝。

回答

6

將值設置爲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,那麼該對象將立即有資格收集。

現在,這一些重要的注意事項:

  1. 首先,沒有充分的理由_newWin是一個成員變量。如果上面的例子是完整的代碼,我們將遷回它是本地DoStuff()並獲得不僅在這個效率的方式,但多,我們的正確性的機會,因爲我們不能做一些愚蠢到_newWin更重要來自另一位成員。
  2. 如果我們持有到的東西在一個成員變量,它可能是一個很好的理由。這個好理由將會超越對儘可能快地清理變量的狂熱。
  3. 無論如何,大多數物體本身並不佔用那麼多的記憶。這裏或那裏的成員變量不會受到傷害。

因此,將null分配給成員變量的主要原因很簡單,因爲null已成爲最合適的值。爲不再使用的成員分配空值通常不是儘快釋放其內存,而是因爲它不再適合使用,而且這變得不可能 - 並且清晰地向您的代碼中的其他代碼發出信號 - 當它一片空白。

如果參考物壽命長於方法(且因此放置在一個成員變量)相當壽命短於包含對象消耗非常大量的存​​儲器,那麼它只是對可能分配null將開始有意義。在發生這種組合的極其罕見的情況下,我們可能希望將它分配給null以指示它不再存在以供班級使用,所以我們仍不會指定空值,其目的是釋放它給了GC。這只是可能的,但真的「沒有」。

0

它不會刪除對象,因爲它會在應用程序中的其他位置引用(在內部代碼中)否則,將_newWin的值設置爲null並使其被垃圾回收會使您的窗口消失(並可能導致您的程序),這沒有發生。

2

垃圾回收不會清空空對象。如果您設置對null的引用,則只需刪除指向對象的引用,以便實際降低其保留計數器。

但是,當一個對象超出範圍而無法被代碼回收時,這個計數器也會減少。所以你試圖做的是無用的。

GC將還是選擇將其釋放,只有當它不再被引用,但如果你顯示的窗口,你一定會在某個地方是無論如何參考..

編輯:在規定評論也許引用計數不是.NET虛擬機的做法(抱歉,但我不使用M $平臺),但原則保持不變。因爲它是可見的,您的窗口無論如何不會被GCed。

+1

注意計數並不是它收集的真實方式。 Afaik它是標記和掃描或類似的。 – Dykam 2010-10-15 14:35:41

+0

@Dykam是正確的,它是標記和掃描。就此而言,它可以在超出範圍之前收集。應該添加詳細的答案。 – 2010-10-15 15:47:03

+0

Mono也沒有引用計數。 – 2010-10-15 16:38:40