C#垃圾回收用法(GC)通俗易懂版

 更新时间:2025年06月17日 10:07:04   作者:终不似少年游啊  
这篇文章主要介绍了C#垃圾回收用法(GC),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

C# 的垃圾回收(Garbage Collection,简称 GC)机制是 .NET 运行时(CLR)的一部分,用于自动管理内存,避免程序员手动释放内存带来的问题(如内存泄漏、悬挂指针等)。

底层实现由 CLR 的 GC 引擎负责,具有高效、安全、并发、分代等特点。

一、为什么需要GC?

想象你的程序是一座繁忙的仓库:

  • 每执行 new Person() 就在仓库中存放一个“货物”(对象)
  • 变量(如 person1)是绑在货物上的“绳子”(引用)
  • 问题:货物不再使用后,若不清理,仓库迟早爆满 → 程序崩溃!

C#的GC就是自动化仓库管理员,默默帮你清扫垃圾、整理货架,彻底告别C/C++时代的手动delete之痛。

二、GC核心四步工作流(超简化版)

1. 暂停世界(Stop-The-World)

  • GC发出指令:“所有线程立刻冻结!”
  • 目的:防止标记过程中对象状态被修改,确保数据一致性。

2. 标记阶段(Mark):谁还在用?

根对象(Roots) 出发:

  • 静态变量(墙上固定的挂钩)
  • 局部变量(操作台上的临时挂钩)
  • CPU寄存器中的引用(管理员手中的绳子)

深度追踪

  • 沿着每根“绳子”找到对象,再检查对象内部的引用(如person1.Dog),像波浪一样扩散标记所有可达对象,并打上“存活”标签。

3. 清扫阶段(Sweep):扔掉垃圾

  • 遍历整个堆内存(仓库)
  • 所有未被标记的对象 → 直接回收其内存!
  • (无任何引用指向 = 程序永远无法访问 = 安全删除)

4. 压缩阶段(Compact):整理碎片

// 压缩前:内存碎片化(空闲但分散)
[对象A][空闲][对象B][空闲][对象C]
// 压缩后:对象紧密排列
[对象A][对象B][对象C][大块连续空闲空间]
  • 移动存活对象到连续地址
  • 更新所有引用(确保“绳子”指向新位置)
  • 关键作用:避免内存碎片,提升后续分配效率!

三、GC高效秘密武器:分代回收(Generations)

洞察规律

“越新的对象,越容易变成垃圾;活得越久,越可能长寿。”

.NET将堆内存分为三代

代际对象特点GC检查频率回收成本
Gen0新创建的小对象(如临时变量)非常高
Gen1经历1次GC仍存活的对象中等
Gen2长期存活对象(如全局缓存)非常低

工作策略

  • 新对象默认进入Gen0
  • Gen0满 → 触发GC(仅回收Gen0,速度极快)
  • Gen0存活对象晋升Gen1
  • Gen1满 → 回收Gen0+Gen1
  • Gen2满 → 完全GC(回收所有代,性能影响大)

优势:90%的垃圾在Gen0被回收,避免频繁扫描老对象!

四、对开发者的关键启示

1. 无需手动释放,但需“断开引用”

让对象变垃圾的正确方式:

// 方法1:引用置空
person1 = null; 

// 方法2:超出作用域(局部变量自动失效)
void CreateTempObject() {
    var temp = new Object(); // 函数结束 → temp引用消失
}

// 方法3:重新赋值
person1 = new Person(); // 原对象失去引用

2. 特殊资源需手动释放!

GC只回收内存!文件句柄、数据库连接等需通过IDisposable主动释放:

// 正确姿势:using自动调用Dispose()
using (var file = File.Open("test.txt")) 
{
    // 操作文件...
} // 离开区域自动关闭文件!

// 等价于手动try-finally
try {
    var file = File.Open("test.txt");
    // ...
} finally {
    file?.Dispose();
}

3. 性能敏感场景优化建议

  • 避免高频创建临时对象(如循环内new
  • 慎用GC.Collect()(强制GC可能引发卡顿)
  • 大对象用Large Object Heap(避免Gen0碎片)
  • 值类型(struct)优先(分配在栈,无GC压力)

五、总结

GC如何改变编程?

传统语言(C/C++)C#/Java(带GC)
手动malloc/free自动创建回收
内存泄漏风险高泄漏概率大幅降低
野指针引发崩溃引用永远指向有效对象
开发效率低专注业务逻辑,生产力↑↑↑

GC哲学:把内存管理的脏活累活交给运行时,让开发者更专注于创造价值!

附:GC触发时机

  • Gen0已满(最常见)
  • 系统物理内存不足
  • 程序主动调用GC.Collect()(不推荐)
  • AppDomain卸载或程序关闭

C# 的 GC 通过分代回收标记 - 压缩算法,自动管理内存,提高开发效率。理解其原理有助于写出更高效的代码,减少 GC 触发频率和 STW(Stop-The-World) 时间。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • C#连接加密的Sqlite数据库的方法

    C#连接加密的Sqlite数据库的方法

    对数据加密分两种,一种是对数据库本身进行加密,另一种是对数据表中的数据进行加密,下面通过本文给大家介绍C#连接加密的Sqlite数据库的方法,感兴趣的朋友一起看看吧
    2017-08-08
  • C#中datatable序列化与反序列化实例分析

    C#中datatable序列化与反序列化实例分析

    这篇文章主要介绍了C#中datatable序列化与反序列化,是datatable的常用技巧,需要的朋友可以参考下
    2014-09-09
  • 详细介绍C# 泛型

    详细介绍C# 泛型

    这篇文章主要介绍了C# 泛型的相关资料,帮助大家更好的理解和学习C#,感兴趣的朋友可以了解下
    2020-08-08
  • 浅谈C#六大设计原则

    浅谈C#六大设计原则

    这篇文章主要介绍了C#六大设计原则的相关内容,文中代码非常细致,供大家参考和学习,感兴趣的朋友可以了解下
    2020-06-06
  • C#开发Windows服务实例之实现禁止QQ运行

    C#开发Windows服务实例之实现禁止QQ运行

    这篇文章主要介绍了通过C#开发Windows服务,查杀qq进程的服务功能,需要的朋友可以参考下
    2013-10-10
  • unity实现简单贪吃蛇游戏

    unity实现简单贪吃蛇游戏

    这篇文章主要为大家详细介绍了unity实现简单贪吃蛇游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04
  • Unity ScrollView实现无限滑动效果

    Unity ScrollView实现无限滑动效果

    这篇文章主要为大家详细介绍了Unity ScrollView实现无限滑动效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-07-07
  • C#中字符串合并的多种实现方法

    C#中字符串合并的多种实现方法

    字符串合并是将两个或多个字符串组合成一个单一字符串的过程,在项目开发中非常常见,C#也为我们提供非常多字符串合并方式,下面一起盘点下,感兴趣的小伙伴跟着小编一起来看看吧
    2025-01-01
  • c#中GetType()与Typeof()的区别

    c#中GetType()与Typeof()的区别

    c#中GetType()与Typeof()的区别,需要的朋友可以参考一下
    2013-04-04
  • C#在WinForm中使用WebKit传递js对象实现与网页交互的方法

    C#在WinForm中使用WebKit传递js对象实现与网页交互的方法

    这篇文章主要介绍了C#在WinForm中使用WebKit传递js对象实现与网页交互的方法,涉及针对WebBroswer控件及WebKit控件的相关使用技巧,需要的朋友可以参考下
    2016-03-03

最新评论