C# GC 垃圾回收机制原理
轉載參照自以下文章:
http://www.cnblogs.com/fdyang/p/3456258.html (c#) 銷毀資源和釋放內存
https://www.cnblogs.com/Jessy/articles/2552839.html C# Finalize和Dispose的區別
https://www.cnblogs.com/wuyuankun/p/4103620.html C#中標準Dispose模式的實現
1,什么是資源:
所謂的資源就是程序中可利用的數據,譬如:字符串、圖片和任何二進制數據,包括任何類型的文件。
2,訪問資源的步驟:
1)分配內存:分配一定的內存空間。
2) ?初始化內存: 一個類型的實例構造器負責這樣的初始化工作。
3)使用資源: 通過訪問類型成員來使用資源。根據需要會有反復。
4)銷毀資源: 執行清理工作。
什么是托管資源,非托管資源:托管資源是由CLR全權負責的資源,CLR不負責的資源位非托管資源。
對于托管資源通過GC自動清理回收。對于非托管資源,通過代碼調用手動進行清除,再由GC回收。
如何正確的釋放資源:對于非托管的資源,一般就是,Stream(流),數據庫的連接,網絡連接等的這些操作系統資源,需要我們手動去釋放。
Net提供了三種釋放方法:Dispose,Close,析構函數(也就是Finalize方法)
第一種:提供Close方法:
介紹:關閉對象資源,在顯示調用時被調用。
Close 表示什么意思,它會不會釋放資源,完全由類設計者決定。因為Close方法是不存在的。你不寫就沒有。那為什么要加一個Close方法呢?為了避免不熟悉C#語法的開發人員更直觀的釋放資源,因此提供了Close方法。提供一個Close方法僅僅是為了更符合其他語言(如C++)的規范。正常情況Close方法里面會調用Dispose()方法。
第二種:Dispose
繼承IDisposable接口,實現Dispose方法;
介紹:調用Dispose方法,銷毀對象,需要顯示調用或者通過using語句,在顯示調用或者離開using程序塊時被調用。
Dispose方法用于清理對象封裝的非托管資源,而不是釋放對象的內存,對象的內存依然由垃圾回收器控制。
Dispose方法調用,不但釋放該類的非托管資源,還釋放了引用的類的非托管資源。
Dispose模式就是一種強制資源清理所要遵守的約定;Dispose模式實現IDisposable接口,從而使得該類型提供一個公有的Dispose方法。
疑問1:Dispose內部到底如何去清理資源的?
第三種:析構函數(也就是Finalize方法)
一個正常情況的類是不會寫析構函數的,而一旦一個類寫了析構函數,就意味著GC會在不確定的時間調用該類的析構函數,判斷該類的資源是否需要釋放,然后調用finalize方法,如果重寫了finalize方法則調用重寫的finalize方法。
Finalize方法的作用是保證.NET對象能在垃圾回收時清除非托管資源。
在.NET中,Object.Finalize()方法是無法重載的,編譯器是根據類的析構函數來自動生成Object.Finalize()方法的
finalize由垃圾回收器調用;dispose由對象調用。
finalize無需擔心因為沒有調用finalize而使非托管資源得不到釋放,因為GC會在不確定時間調用,當然,你也可以手動調用finalize方法,而dispose必須手動調用。
finalize雖然無需擔心因為沒有調用finalize而使非托管資源得不到釋放,但因為由垃圾回收器管理,不能保證立即釋放非托管資源;而dispose一調用便釋放非托管資源。
只有類類型才能重寫finalize,而結構不能;類和結構都能實現IDispose.原因請看Finalize()特性。
雖然可以手動釋放非托管資源,我們仍然要在析構函數中釋放非托管資源,這樣才是安全的應用程序。否則如果因為程序員的疏忽忘記了手動釋放非托管資源, 那么就會帶來災難性的后果。所以說在析構函數中釋放非托管資源,是一種補救的措施,至少對于大多數類來說是如此。?
由于析構函數的調用將導致GC對對象回收的效率降低,所以如果已經完成了析構函數該干的事情(例如釋放非托管資源),就應當使用SuppressFinalize方法告訴GC不需要再執行某個對象的析構函數。?
析構函數中只能釋放非托管資源而不能對任何托管的對象/資源進行操作。因為你無法預測析構函數的運行時機,所以,當析構函數被執行的時候,也許你進行操作的托管資源已經被釋放了。這樣將導致嚴重的后果。?
在結構上重寫Finalize是不合法的,因為結構是值類型,不在堆上,Finalize是垃圾回收器調用來清理托管堆的,而結構不在堆上。
帶有析構函數的類,生命周期會變長。內存空間需要兩次垃圾回收才會被釋放,導致性能下降。
一個帶有析構的類,它引用了很多其他的類,這將導致這些類都升到第1代。(gc有0,1,2三代回收機制)。
5)釋放內存:托管堆上的內存由GC全權負責, 值引用的在棧上的內存會隨著棧空間的消亡而自動消失。
GC.Collect(); //強制對所有代進行即時垃圾回收
當應用程序代碼中某個確定的點上使用的內存量大量減少時,在這種情況下使用 GC.Collect 方法可能比較合適。
疑問2:
垃圾回收機制的原理?強制垃圾回收是怎么一回事?
?
3,釋放模式:是一種微軟建議的寫法,先手動顯示去釋放資源,如果忘記了,再讓finalize釋放資源。如果dispose調用了,則析構不會再調用(使用SuppressFinalize方法取消析構函數的調用)。
?
其他:
如果引用類型對象不再需要,是否需要顯式=null;答案是:即使不這樣做,GC也會進行垃圾回收。
總結
以上是生活随笔為你收集整理的C# GC 垃圾回收机制原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 内存池的实现
- 下一篇: C# Thread开启线程几种方式