.NET垃圾回收(GC)原理
作為.NET進階內容的一部分,垃圾回收器(簡稱GC)是必須瞭解的內容。本著“通俗易懂”的原則,本文將解釋CLR中垃圾回收器的工作原理。
基礎知識
託管堆(Managed Heap)
先來看MSDN的解釋:初始化新程式時,執行時會為程式保留一個連續的地址空間區域。這個保留的地址空間被稱為託管堆。
“託管堆也是堆”,為什麼這樣說呢?這麼說是希望大家不要被“術語”迷惑,這個知識點的前提是“值型別和引用型別的區別”。這裡假設讀者已經知道“值型別儲存在棧中,引用型別儲存在堆中。(引用型別的引用儲存在棧中)”這一重要概念。所以,根據這個理論,除值型別外,CLR要求所有資源都從託管堆分配。
託管堆維護著一個指標,這裡命名為NextObjPtr,它指向下一個物件在堆中的分配位置。
CPU暫存器(CPU Register)
這個是計算機基礎知識,這裡複習一下,有助於對下面“根”概念的理解。
CPU暫存器是CPU自己的”臨時儲存器”,比記憶體的存取還快。按與CPU遠近來分,離得最近的是暫存器,然後快取(計算機一、二、三級快取),最後記憶體。
根(Roots)
類中定義的任何靜態欄位,方法的引數,區域性變數(僅限引用型別變數)等都是根,另外cpu暫存器中的物件指標也是根。根是CLR在堆之外可以找到的各種入口點。
物件可達與不可達(Objects reachable and unreachable)
如果一個根引用了堆中的一個物件,則該物件為“可達”,否則即是“不可達”。
垃圾回收的原因
從計算機組成的角度來講,所有的程式都是要駐留在記憶體中執行的。而記憶體是一個限制因素(大小)。除此之外,託管堆也有大小限制。如果託管堆沒有大小限制,那C#的執行速度要優於c了(託管堆的結構讓它有比c執行時堆更快的物件分配速度)。因為地址空間和儲存的限制因素,託管堆要通過垃圾回收機制,來維持它的正常運作,保證物件的分配,不會“記憶體溢位”。
垃圾回收的基本原理
回收分為兩個階段: 標記 –> 壓縮
標記的過程,其實就是判斷物件是否可達的過程。當所有的根都檢查完畢後,堆中將包含可達(已標記)與不可達(未標記)物件。
標記完成後,進入壓縮階段。在這個階段中,垃圾回收器線性的遍歷堆,以尋找不可達物件的連續記憶體塊。並把可達物件移動到這裡以壓縮堆。這個過程有點類似於磁碟空間的碎片整理。
如上圖所示,綠色框表示可達物件,黃色框為不可達物件。不可達物件清除後,移動可達物件實現記憶體壓縮(變得更緊湊)。
壓縮之後,“指向這些物件的指標”的變數和CPU暫存器現在都會失效,垃圾回收器必須重新訪問所有根,並修改它們來指向物件的新記憶體位置。這會造成顯著的效能損失。這個損失也是託管堆的主要缺點。
基於以上特點,垃圾回收引發的回收演算法也是一項研究課題。因為如果真等到託管堆滿才開始執行垃圾回收,那就真的太“慢”了。
垃圾回收演算法 – 分代(Generation)演算法
代是CLR垃圾回收器採用的一種機制,它唯一的目的就是提升應用程式的效能。分代回收,速度顯然快於回收整個堆。
CLR託管堆支援3代:第0代,第1代,第2代。第0代的空間約為256KB,第1代約為2M,第2代約為10M。新構造的物件會被分配到第0代,
如上圖所示,當第0代的空間滿時,垃圾回收器啟動回收,不可達物件(上圖C、E)會被回收,存活的物件被歸為第1代。
當第0代空間已滿,第1代也開始有很多不可達物件以至空間將滿時,這時兩代垃圾都將被回收。存活下來的物件(可達物件),第0代升為第1代,第1代升為第2代。
實際CLR的代回收機制更加“智慧”,如果新建立的物件生存週期很短,第0代垃圾也會立刻被垃圾回收器回收(不用等空間分配滿)。另外,如果回收了第0代,發現還有很多物件“可達”,
並沒有釋放多少記憶體,就會增大第0代的預算至512KB,回收效果就會轉變為:垃圾回收的次數將減少,但每次都會回收大量的記憶體。如果還沒有釋放多少記憶體,垃圾回收器將執行
完全回收(3代),如果還是不夠,則會丟擲“記憶體溢位”異常。
也就是說,垃圾回收器會根據回收記憶體的大小,動態的調整每一代的分配空間預算!達到自動優化!
總結
垃圾回收背後有這樣一個基本的觀念:程式語言(大多數的)似乎總能訪問無限的記憶體。而開發者可以一直分配、分配再分配——像魔法一樣,取之不盡用之不竭。
.NET垃圾回收器的基本工作原理是:通過最基本的標記清除原理,清除不可達物件;再像磁碟碎片整理一樣壓縮、整理可用記憶體;最後通過分代演算法實現效能最優化。
相關文章
- .Net平臺的GC垃圾回收GC
- Unity GC垃圾回收UnityGC
- Java——GC(垃圾回收)JavaGC
- GC垃圾回收器GC
- .NET垃圾回收(GC)機制效能優化方案GC優化
- 十種GC垃圾回收器GC
- 託管堆和垃圾回收(GC)GC
- 深入理解Java的垃圾回收機制(GC)實現原理JavaGC
- GC 分代回收 - 垃圾收集器GC
- 聊聊JVM的垃圾回收機制GCJVMGC
- 秋招乾貨 - JVM 垃圾回收(GC)JVMGC
- JVM學習(二)——GC垃圾回收機制JVMGC
- JDK 18 GC垃圾回收機制比較JDKGC
- GC垃圾回收機制: 淺析與理解GC
- 【JVM第八篇--垃圾回收】GC和GC演算法JVMGC演算法
- [Inside HotSpot] Serial垃圾回收器Full GCIDEHotSpotGC
- java學習筆記-4 JVM垃圾回收(GC)Java筆記JVMGC
- JVM垃圾回收——新生代,老年代,永久代,Minor GC,Full GCJVMGC
- 【Android面試-Java-V05】Java GC 垃圾回收Android面試JavaGC
- [Inside HotSpot] Serial垃圾回收器 (二) Minor GCIDEHotSpotGC
- 為什麼GC(垃圾回收)必須stop-the-world?GC
- .NET記憶體管理、垃圾回收記憶體
- 垃圾回收演算法|GC標記-清除演算法演算法GC
- JVM必備基礎知識(三)-- GC垃圾回收機制JVMGC
- 面試官,不要再問我“Java GC垃圾回收機制”了面試JavaGC
- 關於lua垃圾回收是否會執行__gc函式呢?GC函式
- Java 22中三種垃圾回收GC效能獲得了大提升JavaGC
- 垃圾回收(一)【垃圾回收的基礎】
- php底層原理之垃圾回收機制PHP
- 從C#垃圾回收(GC)機制中挖掘效能優化方案C#GC優化
- Java虛擬機器5:Java垃圾回收(GC)機制詳解Java虛擬機GC
- .Net Core 中GC的工作原理GC
- JVM 垃圾回收演算法和垃圾回收器JVM演算法
- 精華推薦 | 【JVM深層系列】「GC底層調優系列」一文帶你徹底加強夯實底層原理之GC垃圾回收技術的分析指南(GC原理透析)JVMGC
- jvm:記憶體模型、記憶體分配及GC垃圾回收機制JVM記憶體模型GC
- Java虛擬機器-GC垃圾回收演算法-引用計數法Java虛擬機GC演算法
- Java gc(垃圾回收機制)小結,以及Android優化建議JavaGCAndroid優化
- 垃圾回收機制GC從JDK 8到JDK 17的效能提升 - kstefanjGCJDK