根:類中定義的任何靜態字段,方法的參數,局部變量(僅限引用類型變量)等都是根,另外cpu寄存器中的對象指針也是根 。根是在堆以外能夠找到的各類入口點。程序員
對象可達與不可達:若是一個根引用了堆中的一個對象,則該對象爲可達,不然是不可達。算法
垃圾回收的基本原理:回收分爲兩個階段:標記和壓縮,標記的過程就是判斷對象是否可達的過程。當全部的根檢查完畢後,堆中將包含可達(已標記)與不可達(未標記)對象。數據庫
標記完成後,進入壓縮階段。在這個階段中,垃圾回收器線性遍歷堆,以尋找不可達對象的連續內存塊。並把可達對象移動到這裏以壓縮堆。這個過程有點相似於磁盤空間的碎片整理。安全
不可達對象清除後,移動可達對象實現內存壓縮。網絡
壓縮以後,指向這些對象的指針和cpu寄存器都會失效,垃圾回收器必須從新訪問全部根,並修改他們來指向對象的新內存位置。這會形成顯著的性能損失。這個損失也是託管堆的主要缺點。函數
垃圾回收算法-分代算法性能
代是CLR垃圾回收器採用的一種機制,他惟一的目的就是提高應用程序的性能。分代回收,速度顯然快於回收整個堆。優化
CLR託管堆支持3代:0,1,2。第0代的空間約爲256kb,第一代約爲2m,第二代約爲10m。新構造的對象會被分配到第0代。操作系統
當第0代空間滿時,垃圾回收器啓動回收,不可達對象會被回收,存活的對象會被歸於第1代。指針
當第0代空間已滿,第1代也開始有不少不可達對象以致空間將滿時,這時兩代垃圾都將被回收。存活下來的可達對象,第0代升爲第1代,第1代升爲第2代。
實際CLR的代回收機制更加智能,若是新建立的對象生存週期很短,第0代垃圾也會馬上被垃圾回收器回收(不用等空間分配滿)。另外,若是回收了第0代,發現還有不少對象可達,並無釋放多少內存,就會增大第0代的預算至512kb,回收效果轉變爲:垃圾回收的次數將減小,但每次都會回收大量的內存。若是尚未釋放多少內存,垃圾回收將執行徹底回收(3代),若是還不夠,則會拋出內存異常。
也就是說,垃圾回收器會根據回收內存的大小,動態調整每一代的分配空間預算,達到自動優化。
.NET的GC機制有兩個問題:
首先,GC並非能釋放全部的資源,它不能自動釋放非託管資源。
第二,GC並非實時性的,這將會形成系統性能上的不肯定性。因此有了IDisposable接口,它定義了Dispose方法,這個方法用來供程序員顯式調用以釋放非託管資源。使用using語句能夠簡化資源。
託管資源:託管資源指的是.NET能夠自動進行回收的資源,主要是指託管堆上分配的內存資源。託管資源的回收工做是不須要人工干預的,有.NET運行庫在合適調用垃圾回收器進行回收。
非託管資源:非託管資源指的是.NET不知道如何回收的資源,最多見的一類非託管資源是包裝操做系統資源的對象,例如文件,窗口,網絡鏈接,數據庫鏈接,畫刷,圖標等。這類資源,垃圾回收器在清理的時候會調用Object.Finalize()方法。默認狀況下,方法是空的,對於非託管對象,須要在此方法中編寫回收非託管資源的類,能夠將釋放非託管資源的代碼放在析構函數。
頻繁調用GC.Collect()方法會下降程序的性能,當應用程序代碼中某個肯定的點上使用的內存量大量減小時,在這種狀況下使用 GC.Collect 方法可能比較合適。
.NET提供了三種釋放方法:
第一種:提供Close方法:
關閉對象資源,在顯示調用時被調用。Close方法是不存在的,是使用者本身寫的,正常狀況下Close方法裏面會調用Dispose()方法。
第二種:Dispose
繼承IDisposable接口,實現Dispose方法,調用Dispose方法,銷燬對象,須要顯示調用或者經過using語句,在顯示調用或者離開using程序塊時被調用。
Dispose方法用於清理對象封裝的非託管資源,而不是釋放對象的內存,對象的內存依然由垃圾回收器控制。
Dispose方法調用,不但釋放該類的非託管資源,還釋放了引用的類的非託管資源。
Dispose模式就是一種強制資源清理所要遵照的約定;Dispose模式實現了IDisposable接口,從而使得該類型提供一個公有的Dispose方法。
第三種:析構函數(Finalize)
一個正常狀況的類是不會寫析構函數的,而一旦一個類寫了析構函數,就意味着GC會在不肯定的時間調用該類的析構函數,判斷該類的資源是否須要釋放,而後調用finalize方法,若是重寫了finalize方法則調用重寫的finalize方法,Finalize方法的做用是保證.NET對象能在垃圾回收時清除非託管資源。
在.NET中Object.Finalize方法是沒法重載的,編譯器是根據類的析構函數來自動生成Object.Finalize方法的
finalize由垃圾回收器調用;dispose由對象調用。finalize無需擔憂由於沒有調用finalize而使非託管資源得不到釋放,但由於由垃圾回收器管理,不能保證當即釋放非託管資源;而dispose一調用就釋放非託管資源。
GC.Collect(); //強制對全部代進行即時垃圾回收
當應用程序代碼中某個肯定的點上使用的內存量大量減小時,在這種狀況下使用 GC.Collect 方法可能比較合適。
實現模型:
一、因爲大多數的非託管資源都要求能夠手動釋放,因此,咱們應該專門爲釋放非託管資源公開一個方法。實現IDispose接口的Dispose方法是最好的模型,由於C#支持using語句快,能夠在離開語句塊時自動調用Dispose方法。
二、雖然能夠手動釋放非託管資源,咱們仍然要在析構函數中釋放非託管資源,這樣纔是安全的應用程序。不然若是由於程序員的疏忽忘記了手動釋放非託管資源, 那麼就會帶來災難性的後果。因此說在析構函數中釋放非託管資源,是一種補救的措施,至少對於大多數類來講是如此。
三、因爲析構函數的調用將致使GC對對象回收的效率下降,因此若是已經完成了析構函數該乾的事情(例如釋放非託管資源),就應當使用SuppressFinalize方法告訴GC不須要再執行某個對象的析構函數。
四、析構函數中只能釋放非託管資源而不能對任何託管的對象/資源進行操做。由於你沒法預測析構函數的運行時機,因此,當析構函數被執行的時候,也許你進行操做的託管資源已經被釋放了。這樣將致使嚴重的後果。
五、(這是一個規則)若是一個類擁有一個實現了IDispose接口類型的成員,並建立(注意是建立,而不是接收,必須是由類本身建立)它的實例對象,則 這個類也應該實現IDispose接口,並在Dispose方法中調用全部實現了IDispose接口的成員的Dispose方法。
只有這樣的才能保證全部實現了IDispose接口的類的對象的Dispose方法可以被調用到,確保能夠手動釋聽任何須要釋放的資源。
https://www.jianshu.com/p/26522934afdd