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