常见的垃圾回收算法原理及其模拟实现

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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基础与战略思维…