抽空看了一下.net的垃圾回收機制,感覺這篇文章寫得還不錯,描述比較詳細。 不過還是不怎么懂,分享出來共同學習吧。
垃圾收集器(GarbageCollection)是組成.Net平台一個很重要的部分,.NET垃圾回收機制降低了編程復雜度,使程序員不必分散精力去處理析構。不妨礙設計師進行系統抽象。減少了由於內存運用不當產生的Bug。成功的將內存管理工作從程序的編寫時,脫離至運行時的優點。
-
關於垃圾回收
在.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里面的垃圾回收機制用一定的算法判斷某些內存程序不再使用,回收這些內存並交給我們的程序再使用.
-
垃圾回收的功能
1、用來管理托管資源和非托管資源所占用的內存分配和釋放。
2、尋找不再使用的對象,釋放其占用的內存, 以及釋放非托管資源所占用的內存。
3、垃圾回收器釋放內存之后, 出現了內存碎片, 垃圾回收器移動一些對象, 以得到整塊的內存,同時所有的對象引用都將被調整為指向對象新的存儲位置。
-
回收內存的模式
在.net中提供三種模式來回收內存資源:dispose模式,finalize方法,close方法。
1、dispose提供了一種顯示釋放內存資源的方法。dispose調用方法是:要釋放的資源對象.dispose().
2、finalize方法是.net的內部的一個釋放內存資源的方法。這個方法不對外公開,由垃圾回收器自己調用。
3、close和dispose其實一樣,只不過有的對象沒有提供dispose的方法,只提供了close方法,而close其實在那個對象的類中,依然是調用了一個私有的dispose方法,而finalize其實也是調用一個不對外公開的dispose方法。
-
回收一般過程
1、垃圾回收時機:托管堆滿了,內存分配即將不足時,0代內存分配滿了,或其他情況,微軟沒有公開該部分算法。程序員可以手動調用GC.Collect(),但是會有警告,微軟並不建議這么做。
2、垃圾確認:通過根來尋找可達的對象(以后添加),並做標記,然后回收沒有標記的對象。
3、垃圾回收:內存回收,對於實現了Finalize方法的對象請參考最上面1的介紹。
4、內存轉移,合並。垃圾回收后使得內存不連續,零碎,.Net會將利用的內存合並為連續的塊,然后更新對象的指針。
-
注意的地方
1、值類型(包括引用和對象實例)和引用類型的引用其實是不需要什么"垃圾回收器"來釋放內存的,因為當它們出了作用域后會自動釋放所占內存(因為它們都保存在"堆棧"中,學過數據結構可知這是一種先進后出的結構);
2、只有引用類型的引用所指向的對象實例才保存在"堆"中,而堆因為是一個自由存儲空間,所以它並沒有像"堆棧"那樣有生存期("堆棧"的元素彈出后就代 表生存期結束,也就代表釋放了內存),並且非常要注意的是,"垃圾回收器"只對這塊區域起作用;
3、"垃圾回收器"也許並不像許多人想象的一樣會立即執行(當堆中的資源需要釋放時),而是在引用類型的引用被刪除和它在"堆"中的對象實例被刪除中間有 個間隔,為什么呢? 因為"垃圾回收器"的調用是比較消耗系統資源的,因此不可能經常被調用!(當然,用戶代碼可以用方法System.GC.Collect()來強制執行"垃圾回收器")
4、有析構函數的對象需要垃圾收集器兩次處理才能刪除:第一次調用析構函數時,沒有刪除對象,第二次調用才真正刪除對象。
5、由於垃圾收集器的工作方式,無法確定C#對象的析構函數何時執行。
6、可實現IDisposable接口的Dispose()來顯示釋放由對象使用的所有未托管資源。
7、垃圾收集器在釋放了它能釋放的所有對象后,就會壓縮其他對象,把他們都移動回heap的端部,再次形成一個連續的塊。