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 }
代碼里增加了包含析構器的實現,可以對比一下,性能差異十分明顯。
無析構器的實現結果:
有析構器的實現結果: