C#里可以嵌入非托管代码,这就涉及到了这些代码资源的释放。以前总是看到别人的代码里那么写,也没有好好想想为什么,今天看了书,总结一下。
资源释放分为两种:
- 托管的
- 非托管的
两者的释放方式不一致:
- 没有非托管资源的,GC在运行时,会自动回收和释放;
- 含有非托管资源的,必须提供一个析构器,他们也会在内存里停留的时间会更长,最终被加入一个叫做finalization queue的结构,然后由GC在另一个线程释放;
实现IDispose接口是一种标准的释放资源的方式,正确使用会减少很多的bug和因为资源释放而引起的问题。正如上面所说,包含了非托管资源的代码,是必须提供一个析构器的。这样做的目的,是为了保证类的使用者,即使没有显式地调用Dispose方法,也可以正确地释放资源。
生产环境中的代码里,会有很多的继承,因此为了保证子类在调用时能够正确地执行父类的资源释放,在标准模式中,将真正的资源释放方法Dispose方法,抽象为一个virtual的方法,由子类去override,并在其中调用base的Dispose方法。
释放资源的Dispose方法,应该完成以下几件事(引用Effective C#)
- 释放所有的非托管资源;
- 释放所有的托管资源;
- 设定一个标志,标志资源是否已经销毁;对于销毁的对象,仍旧调用,则应抛异常;
- 跳过终结操作,调用GC.SuppressFinalize(this)方法。
以上,文字内容结束,基本的代码如下:
1 using System; 2 using System.Diagnostics; 3 4 namespace Learn 5 { 6 class Program 7 { 8 private static int Cnt = 100000; 9 10 static void Main(string[] args) 11 { 12 Stopwatch sw = new Stopwatch(); 13 sw.Start(); 14 for (int i = 0; i < Cnt; i++) 15 { 16 IDisposeDerived de = new IDisposeDerived(); 17 } 18 sw.Stop(); 19 Console.WriteLine("total time is: " + sw.ElapsedMilliseconds); 20 Console.ReadLine(); 21 } 22 } 23 24 internal class IDisposeBase : IDisposable 25 { 26 // never add this unless unmanaged resources exist 27 // cauz this will add extra burdon and make negative influence on performance 28 //~IDisposeBase() 29 //{ 30 // Dispose(false); 31 //} 32 33 private bool AlreadyDisposed = false; 34 35 public void Dispose() 36 { 37 Dispose(true); 38 GC.SuppressFinalize(this); 39 } 40 41 protected virtual void Dispose(bool shouldDisposeManagedReources) 42 { 43 if (AlreadyDisposed) 44 return; 45 if (shouldDisposeManagedReources) 46 { 47 // dispose the managed resources 48 // release the events 49 // etc. 50 } 51 // dispose the unmanaged resources 52 53 // set the flag 54 AlreadyDisposed = true; 55 } 56 57 public void MethodForPublic() 58 { 59 if (AlreadyDisposed) 60 throw new Exception("object has been disposed!"); 61 // do the normal things 62 } 63 } 64 65 internal class IDisposeDerived : IDisposeBase 66 { 67 //~IDisposeDerived() 68 //{ 69 // Dispose(false); 70 //} 71 72 private bool AlreadyDisposed = false; 73 74 protected override void Dispose(bool shouldDisposeManagedReources) 75 { 76 if (AlreadyDisposed) 77 return; 78 if (shouldDisposeManagedReources) 79 { 80 // dispose managed resources 81 } 82 // dispose unmanaged resources 83 84 // call the base's dispose method 85 base.Dispose(shouldDisposeManagedReources); 86 87 // set the flag 88 AlreadyDisposed = true; 89 } 90 } 91 }
代码里增加了包含析构器的实现,可以对比一下,性能差异十分明显。
无析构器的实现结果:
有析构器的实现结果: