.NET垃圾回收器(GC)的工作原理
.NET 垃圾回收器(GC)的主要功能是自动管理内存,释放不再使用的对象所占用的内存空间。以下是其详细工作原理:
代的概念
.NET GC 采用了分代垃圾回收的策略,将对象分为三代:第 0 代(Gen 0)、第 1 代(Gen 1)和第 2 代(Gen 2)。新创建的对象会被分配到第 0 代。当第 0 代的对象经历一次垃圾回收后仍然存活,就会被提升到第 1 代;第 1 代的对象在经历一次垃圾回收后仍然存活,就会被提升到第 2 代。
垃圾回收的触发条件
- 内存不足:当系统可用内存低于某个阈值时,会触发垃圾回收。
- 第 0 代对象达到一定数量:当第 0 代中的对象数量达到一定程度时,会触发对第 0 代的垃圾回收。
- 手动触发:可以通过代码手动触发垃圾回收。
垃圾回收的过程
- 标记阶段:GC 会从一组根对象(如全局变量、静态变量、当前线程栈上的变量等)开始,遍历所有可达的对象,并将这些对象标记为“存活”。
- 清除阶段:GC 会清除所有未被标记为“存活”的对象,释放它们所占用的内存空间。
- 压缩阶段:在清除阶段之后,GC 会对存活的对象进行压缩,将它们移动到内存的一端,从而减少内存碎片。
手动触发GC
可以使用 GC.Collect 方法来手动触发垃圾回收。该方法有多个重载版本,常用的有以下两种:
GC.Collect():触发一次完整的垃圾回收,包括对所有代的对象进行回收。GC.Collect(int generation):触发对指定代的对象进行回收。例如,GC.Collect(0)会触发对第 0 代对象的回收。
以下是一个简单的示例代码:
using System;
class Program
{
static void Main()
{
// 创建一些对象
for (int i = 0; i < 1000; i++)
{
object obj = new object();
}
// 手动触发垃圾回收
GC.Collect();
// 输出当前内存使用情况
long memory = GC.GetTotalMemory(true);
Console.WriteLine($"当前内存使用量: {memory} 字节");
}
}
优化GC
以下是一些优化 GC 的建议:
减少对象的创建
频繁创建对象会增加 GC 的负担。可以通过对象池、缓存等技术来减少对象的创建。例如,使用 StringBuilder 来代替频繁的字符串拼接操作:
using System;
using System.Text;
class Program
{
static void Main()
{
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++)
{
sb.Append(i);
}
string result = sb.ToString();
}
}
及时释放非托管资源
对于使用了非托管资源(如文件句柄、数据库连接等)的对象,应该实现 IDisposable 接口,并在使用完后及时调用 Dispose 方法来释放非托管资源。可以使用 using 语句来简化这一过程:
using System;
using System.IO;
class Program
{
static void Main()
{
using (FileStream fs = new FileStream("test.txt", FileMode.Open))
{
// 使用文件流进行操作
} // 离开 using 语句块时,文件流会自动关闭并释放资源
}
}
避免大对象的频繁创建
大对象(如大型数组)会被分配到大型对象堆(LOH)中。LOH 的垃圾回收效率较低,因此应尽量避免频繁创建大对象。
2636

被折叠的 条评论
为什么被折叠?



