.NET CLR GC的知識點彙總
-
GC的處理流程算法
- GC暫停進程中的全部線程。
- GC遍歷堆中的全部對象,將某個位(這個位包含在對象同步塊索引的字段中)設置爲0(0表示將被刪除)。
- GC檢查全部活動根(根是指引用類型的變量),把活動根指向的對象標記爲1,再次該對象引用的其它對象標記爲1,依次類推。
- GC將活動對象進行從新排列,讓全部倖存對象在內存中緊挨在一塊兒。
- 將移動過的倖存對象的根更新固定的偏移量。
- GC恢復進程中的全部線程。
-
GC對活動對象(活動根)的認定:性能
- 被任何靜態對象或靜態字段引用。
- 應用程序棧中引用類型的變量指向的對象。
- 應用程序中的本地引用類型變量。
- 應用程序方法中的引用類型參數。
- 等待被終結(finalized)的對象。
-
GC將活動對象進行從新排列後得到的好處:線程
- 減小活動對象的內存地址範圍,提高訪問活動對象的性能。
- 讓剩餘的內存空間變成連續的,便於後續分配給新對象。
- 解決原生堆(非託管堆)的內存碎片問題。
-
GC代的算法的出發點:code
- 對象越新,生存期越短。
- 對象越老,生存期越長。
- 回收堆的一部分,速度快於回收整個堆。
-
GC關於代的算法流程:對象
- 初始化堆,接下來分配的全部對象都是0代。
- 某個時間點0代超過預算,觸發一次GC回收。
- 倖存下來的對象從0代提高到1代,此時0代不包含任何對象。
- 對1代對象進行緊湊排列。
- 在0代爲新對象分配內存。
- 一段時間後再次觸發GC對0代進行回收。
- 0代回收結束後發現0代的剩餘空間不夠用,此時會觸發對1代的內存進行GC操做。
- 1代中倖存下來的對象會被提高到2代。
- 對1代對象進行緊湊排列。
- 某個時間後再次觸發GC對0代和1代進行回收。
- 回收結束後發現0代的剩餘空間不夠用,此時會觸發對2代的內存進行GC操做。
- 對1代和2代對象進行緊湊排列。
- 某個時間後GC對0-2代回收完成後,發現1代和2代的剩餘空間太多,此時會對0-2代的內存進行從新分配。
-
GC觸發的時機:索引
- 0代超過預算時。
- 顯式調用System.GC.Collect()
- Windows報告低內存
- AppDomain正在被卸載
- CLR正常關閉時
-
GC與Finalize(終結)方法進程
- Finalize方法用於釋放非託管資源的場景。
- 定義過Finalize方法的對象在分配內存時,會被附加到支持終結的對象列表中。
- GC在標記對象爲可刪除時會檢查支持終結的對象列表是否存在,若是存在則會移到待終結的對象列表中。
- 待終結的對象以及它引用的對象在判斷爲待刪除時,這些對象仍是會被臨時性地提高一個代,讓這些對象存活一會來確保終結操做能正常執行。
- GC利用一個高優先級的線程來檢查待終結的對象列表並調用對象的Finalize方法,Finalize方法完成後將對象引用從該列表中刪除。
- 下一輪GC觸發時剛被終結的對象以及它引用的對象會被正常回收。
-
GC與大對象內存
- ≥85,000KB的對象爲大對象。
- 大對象被分配在獨立的堆地址空間中。
- 大對象老是2代,而且只在2代回收操做時觸發回收。
- 大對象通常不會作緊湊操做。
- 參考資料:
- 《CLR via C# Fourth Edition》 Jeffrey Richter
- Fundamentals of garbage collection
https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals
- C# Garbage Collection Active Rootshttps://stackoverflow.com/questions/8345075/c-sharp-garbage-collection-active-roots
歡迎關注本站公眾號,獲取更多信息