淺談.NET垃圾回收機制


   抽空看了一下.net的垃圾回收機制,感覺這篇文章寫得還不錯,描述比較詳細。 不過還是不怎么懂,分享出來共同學習吧。

  垃圾收集器(GarbageCollection)是組成.Net平台一個很重要的部分,.NET垃圾回收機制降低了編程復雜度,使程序員不必分散精力去處理析構。不妨礙設計師進行系統抽象。減少了由於內存運用不當產生的Bug。成功的將內存管理工作從程序的編寫時,脫離至運行時的優點。

  1. 關於垃圾回收

          在.NET Framework中,內存中的資源(即所有二進制信息的集合)分為"托管資源"和"非托管資源".托管資源必須接受.NET Framework的CLR(通用語言運行時)的管理(諸如內存類型安全性檢查),而非托管資源則不必接受.NET Framework的CLR管理. 需要手動清理垃圾(顯式釋放)。

          托管資源在.NET Framework中又分別存放在兩種地方: "堆棧"和"托管堆"(以下簡稱"堆");規則是,所有的值類型(包括引用和對象實例)和引用類型的引用都存放在"堆棧"中,而所有引用所代表的對象實例都保存在堆中。在C#中,釋放托管資源是可以自動通過"垃圾回收器"完成的(注意,"垃圾回收"機制是.NET Framework的特性,而不是C#的).

          在C++時代,我們需要自己來管理申請內存和釋放內存. 於是有了new, delete關鍵字. 還有的一些內存申請和釋放函數(malloc/free). C++程序必須很好地管理自己的內存, 不然就會造成內存泄漏(Memory leak). 在.net時代, 微軟為開發人員提供了一個強有力的機制--垃圾回收. 垃圾回收機制是CLR的一部分, 我們不用操心內存何時釋放, 我們可以花更多精力關注應用程序的業務邏輯. CLR里面的垃圾回收機制用一定的算法判斷某些內存程序不再使用,回收這些內存並交給我們的程序再使用.

  2.  

     垃圾回收的功能

         1、用來管理托管資源和非托管資源所占用的內存分配和釋放。

         2、尋找不再使用的對象,釋放其占用的內存, 以及釋放非托管資源所占用的內存。

         3、垃圾回收器釋放內存之后, 出現了內存碎片, 垃圾回收器移動一些對象, 以得到整塊的內存,同時所有的對象引用都將被調整為指向對象新的存儲位置。

  3.  

     回收內存的模式

         在.net中提供三種模式來回收內存資源:dispose模式,finalize方法,close方法。

         1、dispose提供了一種顯示釋放內存資源的方法。dispose調用方法是:要釋放的資源對象.dispose().

         2、finalize方法是.net的內部的一個釋放內存資源的方法。這個方法不對外公開,由垃圾回收器自己調用。

         3、close和dispose其實一樣,只不過有的對象沒有提供dispose的方法,只提供了close方法,而close其實在那個對象的類中,依然是調用了一個私有的dispose方法,而finalize其實也是調用一個不對外公開的dispose方法。

  4.  

     回收一般過程

         1、垃圾回收時機:托管堆滿了,內存分配即將不足時,0代內存分配滿了,或其他情況,微軟沒有公開該部分算法。程序員可以手動調用GC.Collect(),但是會有警告,微軟並不建議這么做。

         2、垃圾確認:通過根來尋找可達的對象(以后添加),並做標記,然后回收沒有標記的對象。

         3、垃圾回收:內存回收,對於實現了Finalize方法的對象請參考最上面1的介紹。

         4、內存轉移,合並。垃圾回收后使得內存不連續,零碎,.Net會將利用的內存合並為連續的塊,然后更新對象的指針。

  5.  

     注意的地方

         1、值類型(包括引用和對象實例)和引用類型的引用其實是不需要什么"垃圾回收器"來釋放內存的,因為當它們出了作用域后會自動釋放所占內存(因為它們都保存在"堆棧"中,學過數據結構可知這是一種先進后出的結構);

         2、只有引用類型的引用所指向的對象實例才保存在"堆"中,而堆因為是一個自由存儲空間,所以它並沒有像"堆棧"那樣有生存期("堆棧"的元素彈出后就代 表生存期結束,也就代表釋放了內存),並且非常要注意的是,"垃圾回收器"只對這塊區域起作用; 

         3、"垃圾回收器"也許並不像許多人想象的一樣會立即執行(當堆中的資源需要釋放時),而是在引用類型的引用被刪除和它在"堆"中的對象實例被刪除中間有 個間隔,為什么呢? 因為"垃圾回收器"的調用是比較消耗系統資源的,因此不可能經常被調用!(當然,用戶代碼可以用方法System.GC.Collect()來強制執行"垃圾回收器")

        4、有析構函數的對象需要垃圾收集器兩次處理才能刪除:第一次調用析構函數時,沒有刪除對象,第二次調用才真正刪除對象。

        5、由於垃圾收集器的工作方式,無法確定C#對象的析構函數何時執行。

        6、可實現IDisposable接口的Dispose()來顯示釋放由對象使用的所有未托管資源。

        7、垃圾收集器在釋放了它能釋放的所有對象后,就會壓縮其他對象,把他們都移動回heap的端部,再次形成一個連續的塊。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM