首页 > 代码库 > Dispose and Finalizer in C#

Dispose and Finalizer in C#

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有不好的地方

  1. finalizer的调用时间是不确定的。我们不能主动地调用finalizer,只能当GC时由framework调用。这样对于一些稀缺的系统资源,这是不可接受的。
  2. 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

Dispose and Finalizer in C#