1.为什么要进行垃圾回收
对于托管对象不再使用时,CLR会自动回收分配给对象的内存;而对于非托管资源,CLR将不会对其处理,所以要显式释放非托管资源。
2.析构函数, 终结器, Object.Finalize()
终结器用于释放非托管资源。
终结器是通过覆写Object类的Finalize()来定义的。
对象被垃圾收集器收集时会调用终结器,当调用了GC.SuppressFinalize后,将不再调用对象的终结器(析构函数)。
C#不能重写Object的Finalize()方法,析构函数代替Finalize()的实现
3.IDisposable接口
当需要显式释放非托管资源时,可以实现IDisposable接口。
实现IDisposable的Disposable方法,便于主动释放非托管资源。
使用一个标志变量,防止在多次调用Disposable进行重复清理。
在清理之前,先调用GC.SuppressFinalize,防止调用析构函数重复清理。
在调用Disposable后,通过引发System.Object.DisposedException异常来阻止对象的其他方法调用。
4.实现IDisposable的一些规则
1.创建一个protected virthual void Pispose(bool bDisposeManagedRes)方法.在Dispose()方法中调用该方法并让
bDisposeManagedRes参数为true;而在终结器中调用这个方法并让bDisposeManagedRes为false.
2.在Dispose(bool bDisposeManagedRes)方法中释放所有的非托管资源,而仅当bDisposeManagedRes参数为true时释
放托管资源.(注意,调用对象的Close()方法和Dispose()方法属于释放托管资源).
3.在Dispose()方法中,调用Dispose(bool bDisposeManagedRes)重载方法之后调用GC.SuppressFinalize(this).这样
就可以通知垃圾收集器不必再调用该对象的终结器.
5.using
在使用了实现IDisposable的类时,必须在finally块中调用Dispose()方法,避免发生异常而跳过Dispose的调用.
.Net中提供了另一种方式,可以利用using对Dispose自动调用,即使发生异常也会调用。
例如:
using (Font font3 = new Font("Arial", 10.0f), font4 = new Font("Arial", 10.0f))
{
// Use font3 and font4.
}
using里面有两个对象,在using块执行完毕时,会先调用font4的Dispose,然后再调用font3的
6.何时需要终结器和实现Dispose()
任何包含一处或多处非托管资源的类(比如Windows对象的句柄)必须定义终结器来释放这些资源。
7.示例
public class Foo:System.IDispose{
public Foo()
{
}
private bool bDisposed = false; //是否已经释放了资源
public void Fct()
{
if(bDisposed)
throw new System.ObjectDisposedException("Name of the object"); //在释放资源后,产生异常,避免方法再被调用
}
public void Dispose()
{
Dispose(true);
System.GC.SuppressFinalize(this);
}
~Foo(){Dispose(false);}
protected virtual void Dispose(bool bDisposeManagedRes)
{
if(!bDisposed)
{
bDisposed = true;
//释放非托管资源
if(bDisposeManagedRes)
{
//释放托管资源
}
}
}
}
参考资料:
MSDN, C#和.NET2.0实战, C#图解教程