簡體   English   中英

C# - 垃圾收集

[英]C# - Garbage Collection

好的,所以我理解堆棧和堆(堆棧上的值,堆上的引用)。

當我聲明一個類的新實例時,它會存在於堆上,並在堆棧的內存中引用此點。 我也知道C#是自己的垃圾收集(即它確定何時不再使用實例化的類並回收內存)。

我有兩個問題:

  1. 我對垃圾收集的理解是否正確?
  2. 我可以自己做嗎? 如果是這樣,我自己做這件事有什么好處,或者我應該離開它。

我問,因為我在For循環中有一個方法。 每次循環時,我都會創建一個新類的實例。 在我的腦海中,我把所有這些課程都放在一堆,沒有做任何事情,只是占用記憶,我想盡快擺脫它們以保持整潔!

我是正確理解這個還是我錯過了什么?

好的,所以我理解堆棧和堆(堆棧上的值,堆上的引用

我認為你不了解堆棧和堆。 如果值存在於堆棧中那么整數數組在哪里? 整數是價值觀。 你是否告訴我整數數組將其整數保留在堆棧中? 當你從一個方法中返回一個整數數組時,比如說,其中有一萬個整數,你是告訴我那些一萬個整數被復制到堆棧中了嗎?

當它們存在於堆棧中時,值存在於堆棧中,並且當它們存在於堆上時它們存在於堆上。 事物的類型 與其存儲的生命周期有關的想法是無稽之談。 短期存儲位置在堆棧中; 長期存儲的存儲位置在堆上,並且與它們的類型無關。 一個長期存在的int必須在堆上,與一個類的長期實例相同。

當我聲明一個類的新實例時,它會存在於堆上,並在堆棧的內存中引用此點。

為什么引用必須進入堆棧? 同樣, 引用存儲的生命周期與其類型無關 如果引用的存儲是長期存儲的,則引用將在堆上進行。

我也知道C#是自己的垃圾收集(即它確定何時不再使用實例化的類並回收內存)。

C#語言沒有這樣做; CLR這樣做了。

我對垃圾收集的理解是否正確?

你似乎相信很多關於堆棧和堆的謊言,所以賠率不好,不是。

我可以自己做嗎?

不是在C#中,沒有。

我問,因為我在For循環中有一個方法。 每次循環時,我都會創建一個新類的實例。 在我的腦海中,我把所有這些課程都放在一堆,沒有做任何事情,只是占用記憶,我想盡快擺脫它們以保持整潔!

垃圾收集的全部目的是讓您免於擔心整理。 這就是為什么它被稱為“自動垃圾收集”。 它為你整理。

如果您擔心自己的循環會產生收集壓力 ,並且出於性能原因希望避免收集壓力,那么我建議您采用合並策略。 明確的匯集策略開始是明智的; 那是:

while(whatever)
{
    Frob f = FrobPool.FetchFromPool();
    f.Blah();
    FrobPool.ReturnToPool(f);
}

而不是嘗試使用復活終結器進行自動池化。 除非你是終結語義專家,否則我建議一般反對終結者和對象復活。

如果池中沒有池,則該池當然會分配一個新的Frob。 如果池中有一個,那么它將其移出並將其從池中移除直到它被放回。(如果你忘記將Frob放回池中,GC最終會到達它。)通過追求一個池策略,你導致GC最終將所有Frobs移動到第2代堆,而不是在第0代堆中創建大量的收集壓力。 然后收集壓力消失,因為沒有分配新的Frobs。 如果其他東西正在產生收集壓力,那么Frobs就可以安全地進入第2代堆,很少有人訪問它們。

這當然與您描述的策略完全相反; 匯集策略的重點是讓對象永遠存在 對象游逛永遠是,如果你打算使用它們一件好事。

當然,在通過分析知道由於收集壓力導致性能問題之前,請不要進行這些更改! 在桌面CLR上很少出現這樣的問題; 它在緊湊型CLR上更為常見。

更一般地說,如果你是那種讓記憶管理員按照時間表清理你感到不舒服的人,那么C#就不適合你。 考慮C而不是。

值存在於堆棧上,堆上的引用

這是一個實現細節 沒有什么可以阻止.NET Framework將兩者都存儲在堆棧中。

我也知道C#是自己的垃圾收集

C#與此無關。 這是CLR提供的服務。 VB.NET,F#等都還有垃圾收集。

如果它沒有根強CLR 從內存中刪除的對象。 例如,當您的類實例超出for循環范圍時。 會有一些躺在附近,但他們最終都會被回收,無論是由垃圾收集或程序終止。

我可以自己做嗎? 如果是這樣,我自己這樣做有什么好處,還是我應該離開呢?

您可以使用GC.Collect強制收集。 你不應該這樣做,因為這是一項昂貴的操作。 讓一些物品占用內存的時間比絕對需要的時間長一些。 GC非常擅長自己的工作。 你也會強迫短命的物體升級到他們不會正常的世代。

首先, 關於價值類型真相的 Erics開創性帖子

其次,關於垃圾收集,收集器對你運行程序的了解遠遠超過你所知道的,不要試圖再次猜測它,除非你遇到內存泄漏的極不可能的情況。

所以對於你的第二個問題,不要試圖“幫助”GC。

我會在CG上找到一個這樣的帖子並更新這個答案。

我可以自己做嗎? 如果是這樣,我自己做這件事有什么好處,或者我應該離開它。

是的,你可以使用GC.Collect 但你不應該 GC針對短期變量,方法變量和長壽命變量進行了優化,這些變量通常會在應用程序的生命周期內保持不變。

介於兩者之間的變量並不常見,對GC來說並不是最佳選擇。

通過強制GC.Collect,你更有可能導致范圍內的變量被強制進入中間狀態,這與你試圖完成的情況相反。

另請參閱MSDN文章編寫高性能托管應用程序:入門

GC是自我調整的,可根據應用程序內存要求進行自我調整。 在大多數情況下,以編程方式調用GC將阻礙調整。 通過調用GC.Collect“幫助”GC很可能無法提高應用程序性能

您對垃圾收集的理解已經足夠了。 從本質上講,未引用的實例被視為超出范圍且不再需要。 確定了這一點后,收集器將在未來某個時刻刪除未引用的對象。

沒有辦法強制垃圾收集器只收集一個特定的實例。 您可以要求它執行正常的“收集所有可能的”操作GC.Collect() ,但您不應該這樣做。 如果你把它留在自己的設備上,垃圾收集器是高效和有效的。

特別是它擅長收集壽命短的對象,就像那些作為臨時對象創建的對象一樣。 您不必擔心在循環中創建對象的負載,除非它們具有阻止立即收集的長壽命。

請參閱有關堆棧和堆的相關問題

在您的特定場景中,同意,如果您在for循環中新建對象,那么您將獲得次優性能。 對象是在循環中存儲(或以其他方式使用),還是被丟棄? 如果是后者,你可以通過在循環外部新建一個對象並重新使用它來優化它嗎?

關於可以實現自己的GC,C#中沒有明確的刪除關鍵字,您必須將其留給CLR。 然而,您可以給它提示,例如何時收集,或在收集期間忽略什么,但是除非絕對必要,否則我會留下。

最好的祝福,

閱讀Microsoft的以下文章,以獲得有關C#中垃圾收集的一定知識。 我相信它會幫助那些需要有關此事的信息的人。

.NET Framework中的內存管理和垃圾收集

如果您在編寫C#時對代碼中某些區域的性能感興趣,則可以編寫不安全的代碼 您將獲得性能加分,並且在您的固定塊中,垃圾收集器很可能不會發生。

垃圾收集基本上是參考跟蹤。 我想不出有什么理由要你改變它。 你發現內存沒有被釋放,你有什么問題嗎? 或許您正在尋找處置模式

編輯:用“參考跟蹤”替換“引用計數”,不要與對象引用/解除引用的增量/減量計數器混淆(例如從Python)。 我認為將對象圖生成稱為“Counting”是很常見的,就像在這個答案中一樣: 為什么C#中沒有引用計數+垃圾收集? 但我不會拿起(Eric)Eric Lippert的手套:)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM