.NET垃圾回收的機制解釋

首先,對象分爲值類型和引用類型,值類型在用完後是由操作系統自動回收的,引用類型由垃圾回收器回收,所以提到垃圾回收肯定是對引用類型來說的。

垃圾回收機制是爲了解決內存泄漏問題,即對象在用完後,其佔用的內存沒有被釋放,使一個無用的對象不必要的佔用了內存,導致不正常的內存減少甚至耗盡。以前有兩種內存管理技術,一種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接口的方法:

 

View Code
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

 

 

發佈了123 篇原創文章 · 獲贊 14 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章