C#的每个类型都表明一种资源,而资源又分为两类:程序员
若是类型用到了非托管资源,或者须要显式释放托管资源,那么须要让类型继承接口IDisposable。记住:若是类型须要显式释放资源,那么必定要继承IDisposable接口。如:数据库
class SampleClass:IDisposable { private IntPtr nativeResource = Marshal.AllocHGlobal(100);//非托管资源 private Bitmap bitmap = new Bitmap(100, 100);//托管资源 private bool isDisposed = false; //实现IDisposable中的Dispose方法 public void Dispose( ) { Dispose(true); GC.SuppressFinalize(this);//通知垃圾回收器不用再调用终结器 } //没必要要的方法,只是为了符合其余语言的规范 public void Close() { Dispose(); } //必须的,防止程序员忘记显示调用Dispose方法(隐式清理) ~SampleClass() { Dispose(false); } //非密封类修饰用protected virtual,提醒子类必须实现本身的清理方法时注意到父类的清理工做 protected virtual void Dispose(bool isDisposing) { if(isDisposed) { return; } if(isDisposing) { //清理托管资源 if(bitmap != null) { bitmap.Dispose(); bitmap = null; } } //清理非托管资源 if(nativeResource!=IntPtr.Zero) { Marshal.FreeHGlobal(nativeResource); nativeResource = IntPtr.Zero; } isDisposed = false; } public void SamplePublicMethod() { if(isDisposed) { throw new ObjectDisposedException("SampleClass", "SampleClass is disposed"); } //代码 } }
继承IDisposable接口,可使用using语法糖。在using语句代码块内,可使用声明的对象,当语句离开代码块后,系统自动释放资源:ide
//使用using方法,当语句离开代码块后,using内的对象自动释放 using (SampleClass sample = new SampleClass()) { //…… } //以上代码至关于下面的代码 SampleClass sample0 = new SampleClass(); try { //…… } finally { sample0.Dispose(); }
在SampleClass中,存在一个终结器(C++中叫析构器)。其意义在于,调用者可能并不会主动调用Dispose方法,而终结器会被垃圾回收器调用调用,因此它做为释放资源的补救措施。this
在CLR中,每new一个对象时,就会为该对象在堆上分配内存,若是再也不被引用,就会回收它们的内存。若是没有实现IDisposable接口的类型对象,垃圾回收器会直接释放对象所占内存;若是实现了,每次建立对象时,CLR会将该对象的一个指针放到终结列表中,垃圾回收器在回收对象前会首先将终结列表中的指针放入一个freachable队列。同时,CLR会分配一个线程管理freachable队列,调用对象终结器,只有此时,对象才会被真正标识为垃圾,并在下一次进行垃圾回收时释放对象所占内存。即:实现IDisposable接口的类型,至少要通过两次垃圾回收才能真正释放掉内存。其中Dispose方法中的GC.SuppressFinalize()方法用于在显示释放资源后,通知垃圾回收器不用再调用终结器(隐式回收)释放资源。spa
在实现IDisposable接口时,其Dispose()方法并无作实际的清理工做,但提供了带bool参数的受保护的虚方法。由于该类型可能被其余类继承,若是子类实现本身的Dispose模式,受保护的虚方法能够提醒子类:在实现本身的清理方法时,须要注意父类的清理工做(base.Dispose方法)。线程
真正撰写资源释放代码的虚方法有一个bool参数,可是在显示释放资源(true)与隐式释放资源(false)调用中传入的参数不一样。代表:隐式清理时,只须要处理非托管资源就行。托管资源中的普通类型不须要手动清理,而非普通类型须要手动清理。设计
Dispose模式设计思路:若是调用者显示调用了Dispose方法,那么类型循序渐进释放本身的所有资源,而后通知垃圾回收器不须要再释放(GC.SuppressFinalize()方法);而忘记调用Dispose方法,那么类型就假定本身的全部托管资源会所有交给垃圾回收器回收,不须要手动清理。指针