.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垃圾回收器的基本工作原理是:透過最基本的標記清除原理,清除不可達物件;再像磁碟碎片整理一樣壓縮、整理可用記憶體;最後透過分代演算法實現效能最優化。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

C#中常見的記憶體管理問題及解決方法,需要具體程式碼範例在C#開發中,記憶體管理是一個重要的問題,不正確的記憶體管理可能會導致記憶體洩漏和效能問題。本文將向讀者介紹C#中常見的記憶體管理問題,並提供解決方法,並給出具體的程式碼範例。希望能幫助讀者更理解和掌握記憶體管理技術。垃圾回收器不及時釋放資源C#中的垃圾回收器(GarbageCollector)負責自動釋放不再使

C#開發中如何避免記憶體洩漏,需要具體程式碼範例記憶體洩漏是軟體開發過程中常見的問題之一,特別是在使用C#語言進行開發時。記憶體洩漏會導致應用程式佔用越來越多的記憶體空間,最終導致程式運行緩慢甚至崩潰。為了避免記憶體洩漏,我們需要注意一些常見的問題並採取相應措施。及時釋放資源在C#中,使用完資源後一定要及時釋放它們,尤其是涉及文件操作、資料庫連線和網路請求等資源。可以

當今人工智慧(AI)技術的發展如火如荼,它們在各個領域都展現了巨大的潛力和影響力。今天大姚給大家分享4個.NET開源的AI模型LLM相關的專案框架,希望能為大家提供一些參考。 https://github.com/YSGStudyHards/DotNetGuide/blob/main/docs/DotNet/DotNetProjectPicks.mdSemanticKernelSemanticKernel是一種開源的軟體開發工具包(SDK),旨在將大型語言模型(LLM)如OpenAI、Azure

Java中的記憶體管理涉及自動記憶體管理,使用垃圾回收和引用計數來分配、使用和回收記憶體。有效的記憶體管理對於安全性至關重要,因為它可以防止緩衝區溢位、野指標和記憶體洩漏,從而提高程式的安全性。例如,透過正確釋放不再需要的對象,可以避免記憶體洩漏,從而提高程式效能並防止崩潰。

Python開發中遇到的記憶體管理問題及解決方案摘要:在Python開發過程中,記憶體管理是一個重要的問題。本文將討論一些常見的記憶體管理問題,並介紹相應的解決方案,包括引用計數、垃圾回收機制、記憶體分配、記憶體洩漏等。並提供了具體的程式碼範例來幫助讀者更好地理解和應對這些問題。引用計數Python使用引用計數來管理記憶體。引用計數是一種簡單而有效率的記憶體管理方式,它記錄每

如何使用Go語言進行內存優化與垃圾回收Go語言作為一門高效能、並發、效率高的程式語言,對於內存的優化和垃圾回收有著很好的支援。在開發Go程式時,合理地管理和最佳化記憶體使用,能夠提高程式的效能和可靠性。使用適當的資料結構在Go語言中,選擇合適的資料結構對記憶體的使用有很大的影響。例如,對於需要頻繁新增和刪除元素的集合,使用鍊錶代替陣列可以減少記憶體碎片的產生。另外,

Python底層技術解析:如何實現垃圾回收機制,需要具體程式碼範例引言:Python作為一種高階程式語言在開發中極為方便且靈活,但是其底層實作卻是相當複雜的。本文將聚焦在Python的垃圾回收機制,包括垃圾回收的原理、演算法以及具體的實作程式碼範例。希望透過本文對Python垃圾回收機制的解析,讀者能夠更深入了解Python底層技術。一、垃圾回收原理首先,我
