首先,對象分爲值類型和引用類型,值類型在用完後是由操作系統自動回收的,引用類型由垃圾回收器回收,所以提到垃圾回收肯定是對引用類型來說的。
垃圾回收機制是爲了解決內存泄漏問題,即對象在用完後,其佔用的內存沒有被釋放,使一個無用的對象不必要的佔用了內存,導致不正常的內存減少甚至耗盡。以前有兩種內存管理技術,一種COM開發人員熟悉的引用計數技術,一種C++開發人員熟悉的Delete語句,COM開發人員會遇到循環引用的問題,C++開發人員可能忘記Delete,這都會導致內存泄漏。
垃圾回收器在兩種情況下會進行回收,一是自動在適合的時間運行(如內存被耗盡,或Cpu空閒時),一種是顯式調用GC.Collect()來運行。因爲在運行時,它會掛起當前運行的所有線程,所以除非使用了大量的非託管資源或內存大量減少,並且此時已不再需要那些非託管資源,一次性全部釋放這些資源很有意義時,才顯式調用GC.Collect()。
垃圾回收器的執行過程是:
1.在new一個對象的時候,如果這個對象實現了Finallize方法,GC就會在Finallization隊列放一個指向此對象的指針。
2.當垃圾回收器進行內存回收時,對於找到的每一個需要被回收的對象,會先在Finallization隊列中查找是否有指向該對象的指針,如果有則將該指針移到Freachable隊列,沒有則直接回收。
3.當Freachable隊列非空時,激活某特殊線程,逐一執行隊列中每個對象的Finallize方法,然後從本隊列中刪除對象指針,使對象變爲像沒有實現Finallize方法一樣(即在Finallization隊列中沒有指針指向它)的對象,它們將在下一次垃圾回收時進行回收。
4.按一定算法整理內存,在保證效率的情況下,使內存儘量連續。
從上面可以看到實現了Finallize方法對象比沒有實現的對象在垃圾回收時效率低,所以應該儘量避免不必要的Finallize實現。
在C#中,實現Finallize的方法是使用析構函數語法,析構函數在編譯時會被轉換成Finallize。在Finallize方法只能釋放非託管資源,因爲該方法執行的時機不確定,所以當執行時,用到的託管資源可能已經被回收,如果再引用就會出錯。
對於需要資源回收的對象,爲了提高垃圾回收效率,應該儘量實現IDisposable接口,並在Dispose方法中調用GC.SuppressFinallize(this),把對象的指針從Finallization隊列刪除,來防止GC調用Finallize方法。
以下代碼是推薦的實現IDispose接口的方法:
public class MyBase : IDispose 2 3{ 4 5 private Component components; 6 7 private IntPtr handle; 8 9 private bool disposed; 10 11 public void Dispose() 12 13 { 14 15 if(!disposed) 16 17 { 18 19 Dispose(true); 20 21 GC.SuppressFinallize(this); 22 23 } 24 25 } 26 27 protected virtual void Dispose(bool disposing) 28 29 { 30 31 if(!disposed) 32 33 { 34 35 if(disposing) 36 37 { 38 39 if(components!=null) 40 41 components.dispose(); 42 43 } 44 45 CloseHandle(handle); 46 47 handle=IntPtr.Zero; 48 49 disposed=true; 50 51 } 52 53 } 54 55 public void DoSomething() 56 57 { 58 59 if(disposed) 60 61 { 62 63 throw new ObjectDisposedException(); 64 65 } 66 67 } 68 69 ~MyBase() 70 71 { 72 73 Dispose(false); 74 75 } 76 77} 78 79public class MyDerive : MyBase 80 81{ 82 83 private ManagedResource addedManaged; 84 85 private NativeResource addedNative; 86 87 private bool disposed; 88 89 protected override void Dispose(bool disposing) 90 91 { 92 93 if(!disposed) 94 95 { 96 97 try 98 99 { 100 101 if(disposing) 102 103 { 104 105 if(addedManaged!=null) 106 107 addedManaged.Dispose(); 108 109 } 110 111 CloseHandle(addedNative); 112 113 disposed=true; 114 115 } 116 117 finally 118 119 { 120 121 base.Dispose(disposing); 122 123 } 124 125 } 126 127} 128 129
注意,以上代碼不是線程安全的代碼,如果遇到多線程,需要在if(!disposed)外層加上lock(this){}。
轉自周碧文 的博客,原文地址:http://www.cnblogs.com/kofzhoubiwen/archive/2008/06/28/1231641.html