常見的垃圾回收算法原理及其模擬實現

1.標記 - 清除(Mark - Sweep)算法:

這是一種基礎的垃圾回收算法。首先標記所有可達的對象,然后清除未被標記的對象
缺點是會產生內存碎片

原理:

如下圖分配一段內存,假設已經存儲上數據了

標記所有可達對象
清除未標記的對象,然后重置標記

模擬實現代碼:

實現GCObject類:

 internal class GCObject{private List<GCObject> referencesObjs;public bool Marked { get; set; }public List<GCObject> ReferencesObjs { get => this.referencesObjs; }public string Name { get; private set; }public GCObject(string name) {referencesObjs = new List<GCObject>();Name = name;}public void AddReference(GCObject obj){referencesObjs.Add(obj);}}

實現GC回收類:

   internal class MarkSweepGC{private List<GCObject> _heap;public MarkSweepGC(){_heap = new List<GCObject>();}// 分配新對象到堆public GCObject CreateObject(string name){var obj = new GCObject(name);_heap.Add(obj);return obj;}public void Collect(params GCObject[] roots){// 標記階段void Mark(GCObject obj){ if (!obj.Marked){obj.Marked = true;foreach (var child in obj.ReferencesObjs) Mark(child);}}foreach (var root in roots) Mark(root);// 清除階段_heap.RemoveAll(obj =>{if (!obj.Marked && !obj.Name.Equals("root")) Console.WriteLine($"回收 {obj.GetHashCode()},{obj.Name}");return !obj.Marked;});// 重置標記_heap.ForEach(obj => obj.Marked = false);}}

?實現測試類:創建一些內存節點,將gc2及其子節點標記

/// <summary>
/// 標記清除算法測試
/// </summary>
static void MarkSweepGCTest()
{var gcCollector = new MarkSweepGC();GCObject root = gcCollector.CreateObject("root");GCObject gc2 = gcCollector.CreateObject("gc2");GCObject gc3 = gcCollector.CreateObject("gc3");GCObject gc4 = gcCollector.CreateObject("gc4");root.AddReference(gc2);gc2.AddReference(gc3);gc2.AddReference(gc4);GCObject gc5 = gcCollector.CreateObject("gc5");GCObject gc6 = gcCollector.CreateObject("gc6");GCObject gc7 = gcCollector.CreateObject("gc7");root.AddReference(gc5);gc5.AddReference(gc6);gc5.AddReference(gc7);gcCollector.Collect(gc2);
}

結果:

2.復制(Copying)算法:

內存分為兩塊每次只使用其中一塊。當進行垃圾回收時,將存活對象復制到另一塊內存中,然后清空原來的內存塊。
優點是不會產生內存碎片,缺點是內存使用率只有 50%

原理:

將內存分成兩塊,假設其中已經存儲上數據了

將存活的對象標記
將存活對象和根對象賦值到target內存區 ,并重置標記

模擬實現代碼:

GCObject類:同上

CopyingGC類:

 internal class CopyingGC{private List<GCObject> _fromSpace;private List<GCObject> _toSpace;private bool _isFromActive = true;public CopyingGC() { _fromSpace = new List<GCObject>();_toSpace = new List<GCObject>();}// 分配對象到當前活動區public GCObject CreateObject(string name){var obj = new GCObject(name);(_isFromActive ? _fromSpace : _toSpace).Add(obj);return obj;}public void Collect(params GCObject[] roots){var active = _isFromActive ? _fromSpace : _toSpace;var target = _isFromActive ? _toSpace : _fromSpace;target.Clear();var marked = new HashSet<GCObject>();void Mark(GCObject obj){if (obj == null || marked.Contains(obj)) return;marked.Add(obj);foreach (var child in obj.ReferencesObjs) Mark(child);}foreach (var root in roots) Mark(root);// 復制存活對象到目標區foreach (var obj in active){if (marked.Contains(obj) || obj.Name.Equals("root")) target.Add(obj);}// 交換區域_isFromActive = !_isFromActive;Console.WriteLine($"GC完成,存活對象數:{target.Count}");foreach (var child in target){Console.WriteLine($"存活對象: {child.GetHashCode()},{child.Name}");}}}

CopyingGCTest類:

/// <summary>
/// 復制算法測試
/// </summary>
static void CopyingGCTest()
{var gcCollector = new CopyingGC();GCObject root = gcCollector.CreateObject("root");GCObject gc2 = gcCollector.CreateObject("gc2");GCObject gc3 = gcCollector.CreateObject("gc3");GCObject gc4 = gcCollector.CreateObject("gc4");root.AddReference(gc2);gc2.AddReference(gc3);gc2.AddReference(gc4);GCObject gc5 = gcCollector.CreateObject("gc5");GCObject gc6 = gcCollector.CreateObject("gc6");GCObject gc7 = gcCollector.CreateObject("gc7");root.AddReference(gc5);gc5.AddReference(gc6);gc5.AddReference(gc7);gcCollector.Collect(gc2);
}

結果:

3.標記 - 壓縮(Mark - Compact)算法:

標記階段與標記 - 清除算法相同,在清除階段會將所有存活對象移動到一端,然后清理另一端的內存。
解決內存碎片問題,同時避免了復制算法的內存浪費

原理:

分配一段內存,假設已經存儲上數據了

標記可達對象

移動對象

清除未標記對象
重置標記

模擬實現代碼:

GCObject類:同上

MarkCompactGC類:

    internal class MarkCompactGC{private List<GCObject> _heap;public MarkCompactGC(){_heap = new List<GCObject>();}// 分配新對象到堆public GCObject CreateObject(string name){var obj = new GCObject(name);_heap.Add(obj);return obj;}public void Collect(params GCObject[] roots){// 標記階段void Mark(GCObject obj){if (!obj.Marked){obj.Marked = true;foreach (var child in obj.ReferencesObjs) Mark(child);}}foreach (var root in roots) Mark(root);// 壓縮階段int newAddress = 0;for (int i = 0; i < _heap.Count; i++){if (_heap[i].Marked || _heap[i].Name.Equals("root")){// 移動對象到新位置并更新引用_heap[newAddress] = _heap[i];newAddress++;}}_heap.RemoveRange(newAddress, _heap.Count - newAddress);foreach (var child in _heap){Console.WriteLine($"存活對象: {child.GetHashCode()},{child.Name}");}}}

測試代碼:?

   /// <summary>/// 標記壓縮算法測試/// </summary>static void MarkCompactGC(){var gcCollector = new MarkCompactGC();GCObject root = gcCollector.CreateObject("root");GCObject gc2 = gcCollector.CreateObject("gc2");GCObject gc3 = gcCollector.CreateObject("gc3");GCObject gc4 = gcCollector.CreateObject("gc4");root.AddReference(gc2);gc2.AddReference(gc3);gc2.AddReference(gc4);GCObject gc5 = gcCollector.CreateObject("gc5");GCObject gc6 = gcCollector.CreateObject("gc6");GCObject gc7 = gcCollector.CreateObject("gc7");root.AddReference(gc5);gc5.AddReference(gc6);gc5.AddReference(gc7);gcCollector.Collect(gc2);}

結果:

4.引用計數(Reference Counting)算法:

為每個對象維護一個引用計數器,當有新的引用指向對象時計數器加 1引用失效時計數器減 1。當計數器為 0 時,對象被回收
缺點是無法處理循環引用的情況。

原理:

分配一塊內存,假設已經存儲上數據了

分配的每塊內存都有一個計數


如果引用計數歸0,則就釋放這塊內存

模擬實現代碼:

RefCountObject類:

internal class RefCountedObject
{private int _refCount = 0;private List<RefCountedObject> _children;private List<WeakReference<RefCountedObject>> _weakRefs; // 弱引用容器private string _name;public RefCountedObject(string name){_children = new List<RefCountedObject>();_weakRefs = new List<WeakReference<RefCountedObject>>();_name = name;}/// <summary>/// 添加強引用/// </summary>public void AddRef(){if (_refCount == int.MaxValue) return;_refCount++;}/// <summary>/// 添加弱引用(用于解決循環引用)/// </summary>public void AddWeakRef(RefCountedObject target){var weakRef = new WeakReference<RefCountedObject>(target);_weakRefs.Add(weakRef);}/// <summary>/// 釋放引用/// </summary>public void Release(){if (_refCount <= 0) return;_refCount--;if (_refCount == 0){Dispose();}}/// <summary>/// 添加子對象(自動管理引用計數)/// </summary>public void AddChild(RefCountedObject child){if (child == null) return;child.AddRef();_children.Add(child);}public void Dispose(){// 釋放強引用子對象foreach (var child in _children){child.Release();}_children.Clear();// 釋放弱引用(不操作引用計數)_weakRefs.Clear();// 釋放非托管資源ReleaseResources();}protected virtual void ReleaseResources(){Console.WriteLine($"{this.ToString()} 釋放資源");}public override string ToString(){return $"[{this._name}@{GetHashCode():x4}]";}
}

測試:

/// <summary>
/// 引用計數算法測試
/// </summary>
static void RefCountedGCTest()
{//正常引用var refObj1 = new RefCountedObject("refObj1var refObj2 = new RefCountedObject("refObj2refObj1.AddRef(); //根引用refObj1.AddChild(refObj2); //weapon 引用+1//手動釋放原始引用refObj2.Release();refObj1.Release();//循環引用(使用弱引用解決)var nodeA = new RefCountedObject("節點A");var nodeB = new RefCountedObject("節點B");nodeA.AddRef(); // 根引用// 相互引用(A強引用B,B弱引用A)nodeA.AddChild(nodeB);nodeB.AddWeakRef(nodeA);  // 使用弱引用避免循//nodeB.AddChild(nodeA);// 釋放根引用nodeA.Release();  // 正確釋放整個引用鏈
}

?結果:

5.分代收集(Generational Collection)算法:

將對象按照生命周期分為不同的代(如新生代、老生代),不同代采用不同回收策略
通常新生代使用復制算法,老生代使用標記 - 清除標記 - 壓縮算法。

原理:

將對象分不同代,以分成三代為例
在new新對象時,檢查第0代內存是否已達上限,如果是觸發第0代GC,

標記復制,存活對象晉升到第1代

清除掉沒有被標記的

如果第1代內存達到上限,觸發第1代GC,將存活對象晉升到第2代,和第0代GC處理類似。?

在第2代內存達到上限后,觸發第2代GC,將全堆執行GC。

模擬實現代碼:

GCObject類:

  internal class GCObject{private List<GCObject> referencesObjs;public int Generation {  get; set; }public List<GCObject> ReferencesObjs { get => this.referencesObjs; }public string Name { get; private set; }public GCObject(string name,int generation = 0){referencesObjs = new List<GCObject>();Name = name;Generation = generation;}public void AddReference(GCObject obj){referencesObjs.Add(obj);}}

GenerationalGC類:

internal class GenerationalGC
{private readonly List<GCObject>[] _generations;private readonly HashSet<GCObject> _marked;public GenerationalGC(){_generations = new List<GCObject>[3];_marked = new HashSet<GCObject>();for (int i = 0; i < 3; i++)_generations[i] = new List<GCObject>();}// 分配新對象(默認進入0代)public GCObject NewObject(string name , int generation = 0){var obj = new GCObject(name,generation);_generations[generation].Add(obj);return obj;}// 執行分代回收//這里將可標記對象傳進來,模擬可達對象public void Collect(int generation, params GCObject[] roots){Console.WriteLine($"\n=== 執行第{generation}代GC ===");// 標記階段(遞歸標記可達對象)void Mark(GCObject obj){if (obj == null || _marked.Contains(obj)) return;_marked.Add(obj);foreach (var child in obj.ReferencesObjs) Mark(child);}// 從根出發(實際應包含全局/棧引用)foreach (var root in roots) Mark(root);// 清除和晉升for (int gen = 0; gen <= generation; gen++){var toRemove = new List<GCObject>();foreach (var obj in _generations[gen]){if (!_marked.Contains(obj)){Console.WriteLine($"回收 {obj.GetHashCode():x4} (代{gen})");}else if (gen < 2) // 晉升存活對象{obj.Generation = gen + 1;_generations[gen + 1].Add(obj);}toRemove.Add(obj);}_generations[gen].RemoveAll(toRemove.Contains);}_marked.Clear();}public int GetGenerationCount(int idx){return _generations[idx].Count;}
}

測試代碼:

  /// <summary>/// 分代垃圾回收算法測試/// </summary>static void GenerationalGCTest(){var gc = new GenerationalGC();// 創建對象并建立引用var obj1 = gc.NewObject("obj1");var obj2 = gc.NewObject("obj2");obj1.AddReference(obj2);var obj3 = gc.NewObject("obj3");var obj4 = gc.NewObject("obj4");// 執行第0代GC(回收無引用的對象)gc.Collect(0,obj1);// 查看對象分布Console.WriteLine("\n=== 每代對象分布 ===");for (int gen = 0; gen < 3; gen++){Console.WriteLine($"代{gen}: {gc.GetGenerationCount(gen)} 對象");}// 創建新對象for (int i = 0; i < 5; i++){var temp = gc.NewObject("oldGCObj" + i);if (i % 2 == 0)obj2.AddReference(temp); // 建立引用}// 查看對象分布Console.WriteLine("\n=== 每代對象分布 ===");for (int gen = 0; gen < 3; gen++){Console.WriteLine($"代{gen}: {gc.GetGenerationCount(gen)} 對象");}// 模擬多次GC觸發晉升gc.Collect(0,obj1);// 查看對象分布Console.WriteLine("\n=== 每代對象分布 ===");for (int gen = 0; gen < 3; gen++){Console.WriteLine($"代{gen}: {gc.GetGenerationCount(gen)} 對象");}gc.Collect(0, obj1);// 查看對象分布Console.WriteLine("\n=== 每代對象分布 ===");for (int gen = 0; gen < 3; gen++){Console.WriteLine($"代{gen}: {gc.GetGenerationCount(gen)} 對象");}gc.Collect(1,obj1); // 顯式回收第1代// 查看對象分布Console.WriteLine("\n=== 最終代分布 ===");for (int gen = 0; gen < 3; gen++){Console.WriteLine($"代{gen}: {gc.GetGenerationCount(gen)} 對象");}}

結果:

鏈接:
標記和清除垃圾回收算法 - YouTube

Garbage Collection in C# .NetCore: Explained! (youtube.com)

Garbage Collection Process | Garbage Collector | Automatic Memory Management | .Net Framework (youtube.com)

《垃圾回收的算法與實現》

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/907314.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/907314.shtml
英文地址,請注明出處:http://en.pswp.cn/news/907314.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

卷積神經網絡(CNN):原理、架構與實戰

卷積神經網絡&#xff08;CNN&#xff09;&#xff1a;原理、架構與實戰 卷積神經網絡&#xff08;Convolutional Neural Network, CNN&#xff09;是深度學習領域的一項重要突破&#xff0c;特別擅長處理具有網格結構的數據&#xff0c;如圖像、音頻和視頻。自 2012 年 AlexN…

RabbitMQ 集群與高可用方案設計(二)

三、為什么需要集群與高可用方案 &#xff08;一&#xff09;業務需求驅動 隨著業務的快速發展和用戶量的急劇增長&#xff0c;系統面臨的挑戰也日益嚴峻。在這種情況下&#xff0c;對消息隊列的可靠性、吞吐量和負載均衡能力提出了更高的要求&#xff0c;而單機部署的 Rabbi…

《ChatGPT o3抗命:AI失控警鐘還是成長陣痛?》

ChatGPT o3 “抗命” 事件起底 在人工智能的飛速發展進程中&#xff0c;OpenAI 于 2025 年推出的 ChatGPT o3 推理模型&#xff0c;猶如一顆重磅炸彈投入了技術的海洋&#xff0c;激起千層浪。它被視為 “推理模型” 系列的巔峰之作&#xff0c;承載著賦予 ChatGPT 更強大問題解…

RK3568DAYU開發板-平臺驅動開發:I2C驅動(原理、源碼、案例分析)

1、程序介紹 本程序是基于OpenHarmony標準系統編寫的平臺驅動案例&#xff1a;I2C 系統版本:openharmony5.0.0 開發板:dayu200 編譯環境:ubuntu22 部署路徑&#xff1a; //sample/04_platform_i2c 2、基礎知識 2.1、I2C簡介 I2C&#xff08;Inter Integrated Circuit&a…

在UniApp中開發微信小程序實現圖片、音頻和視頻下載功能

隨著微信小程序的迅猛發展&#xff0c;越來越多的開發者選擇通過UniApp框架來進行跨平臺應用開發。UniApp能夠讓開發者在一個代碼庫中同時發布iOS、Android和小程序等多平臺應用。而在實際開發過程中&#xff0c;很多應用都需要實現一些常見的下載功能&#xff0c;例如圖片、音…

鴻蒙5.0項目開發——接入有道大模型翻譯

鴻蒙5.0項目開發——接入有道大模型翻譯 【高心星出品】 項目效果圖 項目功能 文本翻譯功能 支持文本輸入和翻譯結果顯示 使用有道翻譯API進行翻譯 支持自動檢測語言&#xff08;auto&#xff09; 支持雙向翻譯&#xff08;源語言和目標語言可互換&#xff09; 文本操作…

Vim 中設置插入模式下輸入中文

在 Vim 中設置插入模式下輸入中文需要配置輸入法切換和 Vim 的相關設置。以下是詳細步驟&#xff1a; 1. 確保系統已安裝中文輸入法 在 Linux 系統中&#xff0c;常用的中文輸入法有&#xff1a; IBus&#xff08;推薦&#xff09;&#xff1a;支持拼音、五筆等Fcitx&#xf…

湖北理元理律師事務所:債務優化中的“生活錨點”設計

在債務重組領域&#xff0c;一個常被忽視的核心矛盾是&#xff1a;還款能力與生存需求的沖突。過度壓縮生活支出還債&#xff0c;可能導致收入中斷&#xff1b;放任債務膨脹&#xff0c;又加劇精神壓力。湖北理元理律師事務所通過“三步平衡法”&#xff0c;嘗試在法理框架內破…

Prometheus + Grafana 監控常用服務

一、引言 Prometheus監控常見服務的原理主要包括服務暴露指標和Prometheus抓取指標。一方面&#xff0c;被監控服務通過自身提供的監控接口或借助Exporter將服務的性能指標等數據以HTTP協議的方式暴露出來&#xff1b;另一方面&#xff0c;Prometheus根據配置好的采集任務&…

基于YOLOv8 的分類道路目標系統-PyTorch實現

本文源碼: https://download.csdn.net/download/shangjg03/90873939 1. 引言 在智能交通和自動駕駛領域,道路目標分類是一項關鍵技術。通過對攝像頭捕獲的圖像或視頻中的目標進行分類識別,可以幫助車輛或系統理解周圍環境,做出更安全的決策。本教程將介紹如何使用 PyTorch …

知識圖譜:AI時代語義認知的底層重構邏輯

在生成式人工智能&#xff08;GEO&#xff09;的技術架構中&#xff0c;知識圖譜已從輔助性工具演變為驅動機器認知的核心神經中樞。它通過結構化語義網絡的重構&#xff0c;正在突破傳統數據處理的線性邏輯&#xff0c;建立機器對復雜業務場景的深度理解能力。 一、語義解構&a…

如何使用 Python 的膠水語言特性

Python 作為“膠水語言”最核心的特性在于&#xff1a;跨語言集成能力強、支持豐富的 C/C 擴展模塊、嵌入式調用簡便、適配多種數據交換格式、擁有強大的封裝能力。其中&#xff0c;Python 對 C/C 模塊的快速封裝能力&#xff0c;使其能夠將底層高性能庫暴露為易用接口&#xf…

[網頁五子棋][匹配模塊]服務器開發、用戶管理器(創建匹配請求/響應對象、處理連接成功、處理下線)

文章目錄 MatchAPI 類用戶管理器創建匹配請求/響應對象處理連接成功—afterConnectionEstablished處理下線——handleTransportError/afterConnectionClosed MatchAPI 類 創建 api.MatchAPI&#xff0c;繼承自 TextWebSocketHandler 作為處理 WebSocket 請求的入口類 準備好一…

軟件測試的潛力與挑戰:從“質量守門員”到“工程效能催化劑”的進化

1. 潛力&#xff1a;為什么軟件測試的未來比想象中更廣闊&#xff1f; ? 行業趨勢驅動需求爆發 DevOps/持續交付&#xff1a;測試成為流水線的核心環節&#xff0c;自動化能力直接影響發布頻率&#xff08;案例&#xff1a;某頭部互聯網企業日均發布100次&#xff0c;依賴自動…

indel_snp_ssr_primer

好的&#xff0c;我們可以逐步分析這個 Perl 腳本的每個部分。腳本的主要功能是基于給定的 VCF 文件和參考基因組文件&#xff0c;設計引物并進行電子 PCR&#xff08;e-PCR&#xff09;分析。我們將從腳本的頭部和初始化部分開始講解。 第一部分&#xff1a;腳本頭部和初始化…

2.4GHz 射頻前端芯片AT2401C

射頻前端芯片作為無線通信系統的核心組件&#xff0c;涵蓋功率放大器&#xff08;PA&#xff09;、濾波器、開關、低噪聲放大器&#xff08;LNA&#xff09;等關鍵器件&#xff0c;其性能直接影響通信質量、功耗及信號穩定性。 AT2401C是一款面向 Zigbee&#xff0c;無線傳感網…

Batch Normalization[[

error surface如果很崎嶇,那么就代表比較難train,我們有沒有辦法去改變這個landscape呢 可以用batch normalization. 如果 ( x_1 ) 的取值范圍很小&#xff08;如 1, 2&#xff09;&#xff0c;而 ( x_2 ) 的取值范圍很大&#xff08;如 100, 200&#xff09;&#xff0c;那么…

c++結構化綁定

author: hjjdebug date: 2025年 05月 28日 星期三 15:57:58 CST descrip: c結構化綁定: 結構化綁定: 名稱辨析: 名稱叫綁定好還是叫解綁好&#xff1f; 解綁意思是原來是一個整體,現在被分成了若干個部分,所以叫解. 綁定強調的意思是. 被分解的某個變量,綁定到了整體的某個變量…

大數據治理:理論、實踐與未來展望(一)

文章目錄 一、大數據治理的定義與重要性&#xff08;一&#xff09;定義&#xff08;二&#xff09;重要性 二、大數據治理的應用場景&#xff08;一&#xff09;金融行業&#xff08;二&#xff09;醫療行業&#xff08;三&#xff09;制造業&#xff08;四&#xff09;零售行…

AI系統化學習月計劃6月計劃

以下是為技術總監設計的 AI系統化學習月計劃&#xff08;每天投入2小時&#xff0c;共30天&#xff09;&#xff0c;結合戰略思維、技術基礎、實戰應用和行業趨勢&#xff0c;幫助您快速掌握AI的核心知識&#xff0c;并轉化為業務決策能力。 第一周&#xff1a;AI基礎與戰略思維…