.Net内存回收机制

上一篇 / 下一篇  2008-06-28 16:09:41 / 个人分类:C#

1.      WINDOWS系统中,32位处理器上的每个进程最多可以使用4GB的内存。这4GB内存称为虚拟地址空间,或虚拟内存。

2.      值类型存放在堆栈中,引用类型存放在托管堆上。堆栈上的内存总是向下填充的,即由高地址空间向低地址空间填充;托管堆上的内存总是向上填充的,即由低地址空间向高地址空间分配。C#的托管堆与旧未托管堆(如从C++的堆)的区别在于压缩操作,即只要垃圾收集器释放了托管堆上的对象,就会压缩其它对象,把释放的内存块移动到堆的端部,再次形成一个连续的块,就会使为新对象分配内存空间时的速度非常快,这就是C#中创建新对象比C++中创建新对象快的原因。(C++的堆中就没有这种操作,内存释放后,已释放的内存会和未释放的内存混合在一起,导致连续的未被使用的内存块都非常小,这样的话当创建一个新的对象时,运行库必须搜索堆,才能找到足够大的内存块来存放新对象)   (见excel文档)

3.      C++的析构函数相比,C#析构函数的问题是它的不确定性。在删除C++对象时,其析构函数会立即执行。但由于垃圾收集器的工作方式,无法确定C#中的析构函数何时执行。所以不能在C#的析构函数中放置需要在某一时刻运行的代码,也不应使用能以任意顺序对不同类实例调用的析构函数。另一个问题是C#析构函数的执行会延迟对象最终从内存中删除的时间。没有析构函数的对象会在垃圾收集器的一次处理中从内存中删除,但有析构函数的对象需要两次处理才能删除:第一次调用析构函数时,没有删除对象,第二次调用才真正删除对象。另外,运行库使用一个线程来执行所有对象的Finalize()方法。如果频繁使用析构函数,而且使用它们执行长时间的清理任务,对性能的影响就会非常显著。

4.      当垃圾回收器的指针指向托管堆以外的内存空间时,就需要回收内存中的垃圾了。在这个过程中,垃圾回收器首先假设在托管堆中任何的对象都需要被回收。然后他在托管堆中寻找被根对象引用的对象(根对象就是全局,静态或处于活动中的局部变量连同寄存器指向的对象),找到后将他们加入一个有效对象的列表中,并在已搜索过的对象中寻找是否有对象被新加入的有效对象引用。直到垃圾回收器检查完任何的对象后,就有一份根对象和根对象直接或间接引用了的对象的列表,而其他没有在表中的对象就被从内存中回收。

  当对象被加入到托管堆中时,假如他实现了finalize()方法,垃圾回收器会在他的终结

列表(finalization list)中加入一个指向该对象的指针。当该对象被回收时,垃圾回收器

会检查终结列表,看是否需要调用对象的finalize()方法。假如有的话,垃圾回收器将

指向该对象的指针加入一个完成器队列中,该完成器队列保存了那些准备调用finalize()

方法的对象。到了这一步对象还不是真正的垃圾对象。因此垃圾回收器还没有把他们从

托管堆中回收。

  当对象准备被终结时,另一个垃圾回收器线程会调用在完成器队列中每个对象的finalize()方法。当调用完成后,线程将指针从完成器队列中移出,这样垃圾回收器就知道在下

一次回收对象时能够清除被终结的对象了。从上面能够看到垃圾回收机制带来的很大一

部分额外工作就是调用finalize()方法,因此在实际编程中研发人员应该避免在类中实

finalize()方法。

 
对于finalize()方法的另一个问题是研发人员不知道什么时候他将被调用。他不像c++

中的析构函数在删除一个对象时被调用。为了解决这个问题,在.net中提供了一个接口

idisposable微软建议在实现带有fianlize()方法的类的时侯按照下面的模式定义对象:


public class class1 : idisposable 
{
 public class1()
 {
 }

 ~class1 ()
 {
  //垃圾回收器将调用该方法,因此参数需要为false
  dispose (false);
 }

 //该方法定义在idisposable接口中。
 public void dispose ()
 {
  //该方法由程式调用,在调用该方法之后对象将被终结。
  //因为我们不希望垃圾回收器再次终结对象,因此需要从终结列表中去除该对象。
  gc.suppressfinalize (this);
  //因为是由程式调用该方法的,因此参数为true
  dispose (true);
 }

 //任何和回收相关的工作都由该方法完成
 private void dispose(bool disposing)
   {
  lock(this) //避免产生线程错误。
  {
   if (disposing)
   {
    //需要程式员完成释放对象占用的资源。
   }

  //对象将被垃圾回收器终结。在这里添加其他和清除对象相关的代码。
 }
}
}

TAG:

 

评分:0

我来说两句

显示全部

:loveliness: :handshake :victory: :funk: :time: :kiss: :call: :hug: :lol :'( :Q :L ;P :$ :P :o :@ :D :( :)

Open Toolbar