在.NET程序開發中,爲了將開發人員從繁瑣的內存管理中解脫出來,將更多的精力花費在業務邏輯上,CLR提供了自動執行垃圾回收的機制來進行內存管理。開發人員甚至感受不到這一過程的存在。CLR執行垃圾回收的過程,有如下幾點:算法
垃圾回收,第一步要判斷哪些對象須要被GC回收掉。簡而言之,那些在代碼的任何位置也沒法訪問到的對象是須要被GC回收掉的。函數
GC藉助於應用程序根(Application Roots)和對象圖(Object Graph)來判斷哪些對象須要被回收。應用程序根保存了堆上對象的引用,若是一個對象沒有直接或者間接的被應用程序根所引用,那麼就說明沒有任何代碼能夠訪問到它,所以這個對象能夠被回收。性能
應用程序根只是一個入口點,一個對象可能持有其餘一個或者多個對象的引用,這種對象間的引用關係構成了對象圖。每次建立新對象,在複製引用、刪除引用,或者執行垃圾回收以後,CLR都會自動更新它。優化
.NET中的對象建立在託管堆上,託管堆維護着一個指針,這個指針標識了下一個將要建立的新對象所在位置,一般稱做新對象指針。該指針老是位於託管堆的末尾。當使用new運算符建立對象時,CLR將會執行下面幾個主要操做:指針
GC有許多算法,常見的算法有Reference Counting, Mark Sweep, Copy Collection等,目前主流的虛擬系統.NET CLR, Java VM都採用的Mark Sweep算法。Mark-Sweep標記清除階段:先假設Managed Heap中全部對象均可以被回收,而後找出不能回收的對象,給這些對象打上標記,最後Managed Heap中沒有打標記的對象均可以被回收。Compact壓縮階段:對象回收以後Managed Heap內存空間變得不連續,在Managed Heap中移動這些對象,使他們從新從Managed Heap基地址開始連續排列。對象
執行垃圾回收的時機:內存
垃圾回收過程當中還採用了一些優化策略,主要時對象代(Object Generation)和大對象堆(Large Object Heap)開發
對象共分了三個代級:內存管理
當進行垃圾回收時,垃圾回收器將會首先檢查全部的第0代對象,並對其中可回收的對象進行清理。若是清理後得到足夠的空間,經歷過垃圾回收後的對象將提高爲第1代對象。io
若是全部的第0代對象都檢查過了,可是內存空間還不夠,那麼將會檢查第1代對象的可訪問性,並進行垃圾回收。此時,若是經歷過垃圾回收的第1代對象仍保留在堆上,則會升級爲第2代對象。相似的,若是內存仍不夠用,將會對第2代對象進行檢查和垃圾回收。若是第2代的部分對象在這次垃圾回收後仍然保留在堆棧上,它依然是第2代對象。由於總共定義了3代對象。若是第2代對象在進行完垃圾回收後空間依然不夠用,則會拋出OutOfMemoryException異常。
可見,最容易清理掉的就是那些新對象。
垃圾回收的過程當中有一個很影響性能的地方,就是在壓縮的過程當中,由於要批量地挪動對象,以填充騰出來的空間,若是對象很大,那麼要移動的數據量就會很大。
若是將大對象直接分配在第0代,那麼第0代的空間很快就會被佔滿,從而迫使CLR執行一次垃圾回收,這樣執行垃圾回收的次數就會變得很頻繁。
所以,第二個優化策略就是採用大對象堆,當對象大小超過85kb時,就會被分配在大對象堆上。大對象堆有幾個特色:
至此,就對.NET GC有了一個基本的瞭解。感謝您的閱讀~