.Net的GC机制
版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
http://songshp39.blogbus.com/logs/7297695.html
.NET的GC机制有这样两个问题:
首先,GC并不是能释放所有的资源。它不能自动释放非托管资源。
第二,GC并不是实时性的,这将会造成系统性能上的瓶颈和不确定性。
垃圾回收的优缺点
实现垃圾回收有多种方法,每一种方法都提供了不同的性能特征。然而,所有的垃圾回收系统都具有一个共同的、与手工方法相对的属性。垃圾回收最主要的优点是简单和安全。
在垃圾回收环境中,可以显式地使用new分配内存,但是不需要显式地释放内存。相反,不再使用的内存会被自动回收。因此,不可能会忘记释放对象或者过早地释放对象。
这样做简化了程序设计,并且阻止了有问题的类。另外,不可能会意外地两次释放动态分配的内存。因此,垃圾回收为内存管理问题 提供了一种易于使用的、不容易犯错的、
可靠的解决方案。
遗憾的是,垃圾回收的简单及安全性是有代价的。第一个代价是垃圾回收机制引起的开销。所有垃圾回收的配置都会消耗一些CPU资源,因为这种不再使用的内存的回收并不是
一个免费过程。当使用手工方法的时候,不会有这样的开销。
第二个代价是在销毁对象时容易失控。使用手工方法时,当对对象执行delete语句的时候,及时地销毁这个对象(和所调用的它的析构函数),而垃圾回收没有这种切实而快速
的规则。相反,当使用垃圾回收时,直到回收器运行并回收对象的时候,对象才会被销毁,而回收器只有在某个特定时刻才会运行。例如, 回收器只有在自由内存的数量低于
某个值的时候才会运行。另外,用户并不能总是知道垃圾回收器销毁对象的顺序和时间。在某些情况下,不能准确地知道对象销毁 的时间会导致一些问题,因为这意味着程序
不能准确地知道何时为动态分配的对象调用析构函数。
对于作为后台任务运行的垃圾回收系统,这种失控可能会引发某种应用程序潜在的更加严重的问题,因为这样做将某种本质上不确定的行为引入到程序中。在 后台运行的垃圾
回收器实际上在不可预知的某个时刻回收不再使用的内存。例如,回收器通常只有在CPU空闲的时候才会运行。由于可能从一个程序的运行转到下 一个程序,从一台计算机转到
下一台计算机,或者从一个操作系统转到另一个操作系统,因此垃圾回收器在程序中执行的确切位置是不能确定的。对于许多应用程序而言,这并不存在问题,但是对于实时
应用程序这可能会引发灾难,因为在实时应用程序中对垃圾回收器不可预知的CPU循环的分配会导致事件的丢失。
为了解决第一个问题,.NET提供了析构函数,在C#中是~ClassName的形式。如果某个类定义了析构函数,.NET会在第一次的GC中调用析构函数,第二次才真正进行资源释放。
这就允许了我们能够做一些手动的资源管理操作,手动对非托管资源进行清理。但是如果没有必要,定义析构函数就会对性能造成较大的影响。
仅仅依赖析构函数对非托管资源进行释放是不够的,这是由于第二个问题:GC并不是实时性的,这会造成系统性能上的瓶颈和不确定性。所以有了IDisposable接口,
IDisposable接口定义了Dispose方法,这个方法用来供程序员显式调用以释放非托管资源。
通常我们应该这样写程序:
public class SampleClass : System.IDisposable
{
public void Dispose()
//供程序员显式调用的Dispose方法
{
Dispose(true);
//调用带参数的Dispose方法,释放托管和非托管资源
System.GC.SuppressFinalize(this);
//手动调用了Dispose释放资源,那么析构函数就是不必要的了,这里阻止GC调用析构函数
}
protected void Dispose(bool disposing)
//protected的Dispose方法,保证不会被外部调用。
//传入bool值disposing以确定是否释放托管资源
{
if (disposing)
{
//在这里加入清理"托管资源"的代码,应该是xxx.Dispose();
}
// 在这里加入清理"非托管资源"的代码
}
~SampleClass()
//供GC调用的析构函数
{
Dispose(false);
//释放非托管资源
}
}
这样一来,我们就像Delphi里调用Object.Free方法一样自然的调用Object.Dispose方法,而即使我们忘记了在合适的时候调用Dispose,GC也会在释放对象的时候帮
我们清理非托管资源的。GC所充当的角色只是一种保障手段,它应该充当这种角色,我们不能过分依赖它。
实际上,在较大的模块退出时我们还应该及时地手动调用GC.Collect进行垃圾回收。
GC.Collect();
GC.WaitForPendingFinalizers();
GC=Controls the system garbage collector, a service that automatically reclaims unused memory