2012-01-05 106 views
7

在標題從書「C#2010和.NET 4平臺」由安德魯·特羅爾森寫了「強制垃圾保藏中心」不良垃圾收集

「同樣,整個.NET的目的垃圾回收器是代表我們管理內存的,但在一些非常罕見的情況下,使用GC.Collect()強制垃圾回收可能是有益的,具體如下:

•您的應用程序即將進入您不想被可能的垃圾回收中斷的代碼塊。 ... 「

但停!垃圾收集是否是不可取的,是否有這種情況?我從來沒有看到/讀過類似的東西(當然是因爲我的開發經驗很少)。如果在練習時你已經做了這樣的事情,請分享。對我而言,這非常有趣。

謝謝!

+7

請特別注意*「一些非常罕見的情況」*,並且不要在您的代碼中散佈GC.Collect()。 – 2012-01-05 18:03:25

+0

將完成! :) – Arterius 2012-01-05 18:24:15

回答

5

我運行一個配方相關的網站,我在內存中存儲了大量食譜及其配料使用圖。由於我爲快速訪問而轉發此信息的方式,因此在應用程序加載之前,我必須將數據的數據加載到內存中,然後才能將數據組織到非常優化的圖表中。我在堆上創建了大量的小對象,一旦圖創建,就變得無法訪問。

這一切都是在Web應用程序加載時完成的,可能需要4-5秒才能完成。我這樣做後,我打電話GC.Collect();,因爲我寧願重新聲明所有的內存,而不是在傳入的HTTP請求期間阻止所有線程,而垃圾收集器正在清理所有這些短暫的對象。我還認爲現在清理會更好,因爲此時堆可能不太分散,因爲我的應用到目前爲止還沒有真正做過其他任何事情。推遲這可能會導致創建更多的對象,並且GC在自動運行時需要更多地壓縮堆。

除此之外,在我12年的.NET編程中,我從來沒有遇到過要迫使垃圾收集器運行的情況。

7

是的,當垃圾收集不受歡迎時絕對有這種情況:當用戶正在等待某些事情發生時,他們必須等待更長的時間,因爲代碼無法繼續,直到垃圾收集完成。

這是Troelsen的觀點:如果你有,你知道一個GC的特定點問題並且很可能是能夠收集顯著大量垃圾的那麼可以是一個好主意挑起那麼爲了避免它在不太合適的時候觸發它。

+0

你知道這不是問題,甚至比你可能想要... – 2012-01-05 18:16:12

+0

更罕見@TonyHopkinson:這是相對罕見的,但並不是聞所未聞的。更準確地說,你可能很清楚現在比現在要少*有問題。 – 2012-01-05 18:30:50

+0

這總是一個違反規則的理由,不是說你永遠不應該這樣做,只是在你破壞它們之前,你應該瞭解它們,這樣你纔能有效地打破它們。 – 2012-01-05 22:09:04

1

這將是非常罕見的,但GC可能是一個適度昂貴的過程,所以如果有一個特定的時間敏感部分,您不希望該部分被GC中斷。

3

建議您不要在代碼中明確調用Collect。你能找到它有用的情況嗎?

其他有詳細的一些,毫無疑問更多。首先要了解的是,不要做。這是最後的手段,調查其他選項,瞭解GC工作原理如何查看代碼的影響,並遵循最佳實踐來進行設計。

在錯誤的地方撥打Collect會使您的表現變差。更糟的是,依靠它會使你的代碼非常脆弱。撥打Collect所需的罕見條件有益,或者最終無害,可以通過對代碼進行簡單更改而完全撤銷,這會導致意外的OOM,性能低下等。

2

我在性能測量之前稱之爲GC,但不會僞造結果。

另一種情況是內存泄漏單元測試測試:

object doesItLeak = /*...*/; //The object you want to have tested 
WeakReference reference = new WeakRefrence(doesItLeak); 
GC.Collect(); 
GC.WaitForPendingFinalizers(); 
GC.Collect(); 

Assert.That(!reference.IsAlive); 

除了這些,我沒有遇到它實際上是有幫助的情況。
特別是在生產代碼,GC.Collect永遠不會被發現恕我直言。

1

您的應用程序即將進入一個代碼塊,您不希望 希望被可能的垃圾回收中斷。 ...

一個非常可疑的參數(即仍然使用了很多)。

Windows不是實時操作系統。您的代碼(線程/進程)始終可以被OS調度程序預佔。您沒有保證的CPU訪問權限。

所以歸結爲:GC運行時間與時間間隔(〜20 ms)相比如何?

關於這方面的數據很少,我搜索了幾次。

從我自己的觀察(非常非正式的),gen-0集合是012ms40毫秒,通常少得多。完整的gen-2可以運行到〜100 ms,可能更多。

因此,被GC中斷的「風險」與另一個過程換出的風險數量級相同。而你無法控制後者。