C#——垃圾回收(GC)


前言

C#的垃圾回收网上有很多博客进行讲解,这里摘录一部分较好的讲解,同时建议直接使用微软官方文档,万变不离其宗

一、垃圾回收是什么

.NET 的垃圾收集器管理应用程序的内存分配和释放。每次创建新对象时,公共语言运行时都会从托管堆中为该对象分配内存。只要托管堆中有可用的地址空间,运行时就会继续为新对象分配空间。然而,内存并不是无限的。最终垃圾收集器必须执行收集以释放一些内存。垃圾收集器的优化引擎根据进行的分配确定执行收集的最佳时间。当垃圾收集器执行收集时,它会检查托管堆中应用程序不再使用的对象,并执行必要的操作来回收它们的内存。

在公共语言运行时 (CLR) 中,垃圾收集器 (GC) 充当自动内存管理器。垃圾收集器管理应用程序的内存分配和释放。对于使用托管代码的开发人员来说,这意味着不必编写代码来执行内存管理任务。自动内存管理可以消除常见问题,例如忘记释放对象并导致内存泄漏或尝试访问已释放对象的内存。

Garbage Collector(垃圾收集器,在不至于混淆的情况下也成为GC)以应用程序的root为基础,遍历应用程序在Heap上动态分配的所有对象[2],通过识别它们是否被引用来确定哪些对象是已经死亡的、哪些仍需要被使用。已经不再被应用程序的root或者别的对象所引用的对象就是已经死亡的对象,即所谓的垃圾,需要被回收。这就是GC工作的原理。为了实现这个原理,GC有多种算法。比较常见的算法有Reference CountingMark SweepCopy Collection等等。目前主流的虚拟系统.NET CLR,Java VM和Rotor都是采用的Mark Sweep算法。

二、好处

垃圾收集器提供以下好处:

  • 使开发人员不必手动释放内存。
  • 有效地在托管堆上分配对象。
  • 回收不再使用的对象,清除它们的内存,并使内存可用于将来的分配。托管对象会自动获得干净的内容,因此它们的构造函数不必初始化个数据字段。
  • 通过确保一个对象不能为自己使用分配给另一个对象的内存来提供内存安全。

总的说来就是GC可以使程序员可以从复杂的内存问题中摆脱出来,从而提高了软件开发的速度、质量和安全性。

三、GC过程

1.GC条件

  1. If the system has low physical memory, then garbage collection is necessary.(系统内存过低时执行)
  2. If the memory allocated to various objects in the heap memory exceeds a pre-set threshold, then garbage collection occurs.(分配给各个对象的内存超过预先设定阈值)
  3. If the GC.Collect method is called, then garbage collection occurs. However, this method is only called under unusual situations as normally garbage collector runs automatically.(手动调用GC.Collect)

2.GC步骤

GC总体可以分为三个步骤:

  1. 标记(Mark)。从Root开始进行引用标记,未被标记到的为不可达内存,不可达内存为GC对象。
  2. 重新分配地址(Relocate)。更新所有活动对象列表中的所有对象的引用,以便它们指向对象将
### 垃圾回收器工作原理 垃圾回收器的主要目标是在程序运行期间自动管理和释放不再使用的内存。其基本思路是识别并回收那些不再可访问的对象所占用的空间。 #### 标记-清除算法 一种经典的垃圾回收策略被称为「标记-清除」(Mark-Sweep),该方法分为两个主要阶段: - **标记阶段**:遍历所有根节点(通常是栈中的引用),递归地标记所有可达对象。 - **清理阶段**:扫描堆空间,查找未被标记的对象,并将其对应的内存区域回收以供后续再利用[^4]。 此过程中,任何未能通过可达性分析的对象都将被认为是废弃的,进而得到处理。 ### 分代收集机制 为了提升效率,现代JVM采用分代假设理论设计了多级结构化的垃圾收集体系——即所谓的“世代模型”。这种架构下,新生代、老年代各自对应不同频率与方式的清扫动作: - 新生代(Young Generation)通常发生较为频繁的小规模回收事件(Minor GC)。由于大多数新创建的对象很快就会变得不可达,因此这部分内存会被快速周转。 - 当某些存活周期较长的对象经过多次年轻代GC后仍未被淘汰,则迁移到年老代(Old Generation)。针对后者开展的大范围整理行动称为Major/Mixed GC,这类操作相对少见却耗时更久[^1]。 值得注意的是,在Java 8之后版本里,原本用于存储类元数据信息的永久代已被替换成了名为Metaspace的新组件;当这个区域容量不足时同样会引起Full GC的发生[^3]。 ### C# 中的具体实践 对于.NET平台而言,开发者应当注意合理控制应用程序内的对象生命期长度,比如优先选用局部作用域内的临时实例而非长期存在的字段成员,以此降低因过度活跃而导致过早触发GC的风险。另外还需警惕诸如装箱/拆箱转换之类的潜在陷阱,它们可能会间接增加额外开销。最后一点就是务必谨慎对待事件处理器注册行为,防止因为遗漏解除绑定而造成隐性的泄露隐患[^2]。 ```csharp public class DisposableResource : IDisposable { private bool disposed = false; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); // Prevent finalizer from running again. } protected virtual void Dispose(bool disposing) { if (!disposed) { if (disposing) { // Free managed resources here... } // Release unmanaged resources here... disposed = true; } } ~DisposableResource() { // Finalizer as backup cleanup mechanism. Dispose(false); } } ``` 上述代码展示了如何正确实现`IDisposable`接口来确保托管及非托管资源都能得到有效处置[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值