您的位置:首页 > 其它

.NET垃圾回收的机制解释

2012-07-05 11:13 218 查看
首先,对象分为值类型和引用类型,值类型在用完后是由操作系统自动回收的,引用类型由垃圾回收器回收,所以提到垃圾回收肯定是对引用类型来说的。

垃圾回收机制是为了解决内存泄漏问题,即对象在用完后,其占用的内存没有被释放,使一个无用的对象不必要的占用了内存,导致不正常的内存减少甚至耗尽。以前有两种内存管理技术,一种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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: