CLR提供了自动内存管理。Managed memory不需要我们显式地释放。当进行Garbage Collection时,会自动释放。
但是,managed memory仅仅是许多种系统资源中的一种。除了managed memory之外的其他需要显式地释放的资源,被称为unmanaged resources,比如打开的文件描述符,打开的数据库连接等。
CLR提供了释放unmanaged resources的机制。System.Object中声明了一个virtual 方法 Finalize,该方法类似C++中的析构函数,当一个object的内存被回收时,GC会调用Finalize方法释放unmanaged resources。重写了Finalizer的类型也叫做Finalizable类型。
public class ComplexResourceHolder : IDisposable {
private IntPtr buffer; // unmanaged memory buffer
private SafeHandle resource; // disposable handle to a resource
public ComplexResourceHolder(){
this.buffer = ... // allocates memory
this.resource = ... // allocates the resource
}
~ ComplexResourceHolder(){
ReleaseBuffer(buffer); // release unmanaged memory
}
}
但是使用finalizer有不好的地方
- finalizer的调用时间是不确定的。我们不能主动地调用finalizer,只能当GC时由framework调用。这样对于一些稀缺的系统资源,这是不可接受的。
- 当GC准备回收一个对象的内存时,如果该对象需要finalize,那么会把该对象放到一个finalize队列中,然后另外一个线程会从该队列中取出对象并调用finalizer。这样,这个对象的内存最快要到下次GC(也有可能第三次、第四次)时才能被回收。因此可能会降低性能。
.Net Framework提供了System.IDisposable接口,通过实现该接口的Dispose方法,我们可以手动调用该方法,这样就可以自己控制unmanaged resources的释放时间。Framework也提供了GC.SuppressFinalize方法告诉GC该对象已经被手动disposed,不需要finalized。这样,该对象的内存就可以被尽快地回收。
.Net推荐的IDisposable接口实现方式如下
public class ComplexResourceHolder : IDisposable {
private IntPtr buffer; // unmanaged memory buffer
private SafeHandle resource; // disposable handle to a resource
public ComplexResourceHolder(){
this.buffer = ... // allocates memory
this.resource = ... // allocates the resource
}
// Implement IDisposable.
// Do not make this method virtual.
// A derived class should not be able to override this method.
public void Dispose(){
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
// Use C# destructor syntax for finalization code.
// This destructor will run only if the Dispose method
// does not get called.
// It gives your base class the opportunity to finalize.
// Do not provide destructors in types derived from this class.
~ComplexResourceHolder(){
Dispose(false);
}
// Dispose(bool disposing) executes in two distinct scenarios.
// If disposing equals true, the method has been called directly
// or indirectly by a user's code. Managed and unmanaged resources
// can be disposed.
// If disposing equals false, the method has been called by the
// runtime from inside the finalizer and you should not reference
// other objects. Only unmanaged resources can be disposed.
protected virtual void Dispose(bool disposing){
// release unmanaged memory
ReleaseBuffer(buffer);
// release other disposable objects
if (disposing){
if (resource!= null)
resource.Dispose();
}
}
}
Reference:
1. http://msdn.microsoft.com/zh-cn/library/system.idisposable.dispose(v=vs.110).aspx
2. http://msdn.microsoft.com/en-us/library/b1yfkh5e(v=vs.110).aspx
3. http://msdn.microsoft.com/en-us/magazine/bb985010.aspx It describes how finalize works internal