keni:CLR无用内存回收学习笔记(2)


l         Finalize
在上一篇文章中我分配使用资源一共五步,我们已经知道了GC是如何释放无用对象的内存了。但是它怎么实现第四步清空资源使用状态、释放利用到的一些非内存的系统资源呢?.NET引入了Finalize来完成这个任务。
引用了系统资源才需要override Finalize()方法。
GC在无用单元回收时一旦发现某个对象有Finalize方法,便调用它。所以我们的Finalize方法一定要尽量少做事情,以提高内存回收的速度。另外,在Finalize方法中不要有任何的线程同步等操作,以防止GC线程被挂起。
我们可以用两种方法来写自己的Finalize方法。一种就是显示的实现,如下面的代码:
代码1
public class SomeClass
{
   public SomeClass()
   {
   }
 
   protected override void Finalize()
   {
      Console.WriteLine(“Finalizing…”);
   }
}
使用这种方法时要注意一点,.NET不会帮你做调用基类的Finalize方法。如果需要调用基类的Finalize方法,需要显示的调用。如下面代码:
代码2
public class SomeClass
{
   public SomeClass()
   {
   }
 
   protected override void Finalize()
   {
      Console.WriteLine(“Finalizing…”);
      base.Finalize(); // 调用基类Finalize方法
   }
}
另外一种方法就是析构函数。C#中的析构函数不同于C++。我们看下面的代码:
代码3
public class SomeClass
{
   public SomeClass()
   {
   }
 
   ~SomeClass()
   {
      Console.WriteLine(“Finalizing…”);
   }
}
它等同于代码2。
使用Finalize方法要特别小心。因为使用Finalize方法的对象要比普通的对象花时间;GC也要花更多的时间来回收。而且CLR并不能保证调用Finalize的顺序,所以如果对象间有关联(比如一个成员变量先被Finalize了,如果在Finalize方法里还使用它,就会出错),就会更麻烦。
GC是如何实现Finalize的呢?GC维护了两个队列,Finalization队列和Freachable队列。在托管堆分配对象的时候,GC如果发现这个对象实现了一个Finalize方法,就把它加到Finalization队列。如图:
当托管堆的内存不足的时候,GC开始对堆进行回收。GC回收一个对象前,先检查Finalization队列中是否有这个对象的指针,如果有,就将其放入Freachable队列。Freachable队列被认为是根(root)的一部分,所以GC不会对其作回收。GC第一次回收后,堆如下图:
对象G和对象E不在根的范围之内,被回收。对象F和对象C由于需要Finalize被放入到Freachable队列,这个队列被认为是根的一部分,所以这是对象F和对象C就复活了,没有被GC回收。Freachable队列中的对象的Finalize方法被一个特殊的线程执行。这个线程平时处于非活动状态,一旦Freachable队列不再为空,它就醒过来,一一执行这个队列中对象中的Finalize方法。执行过后如下图:
这时对象F和对象C不再是根的一部分,如果此时GC进行回收,将会被认作无用对象进行回收,回收后如下图:
上面简单描述了Finalize作用及其内部的工作原理。下面来说一下Generation。
l         Generation
每次都对整个对进行搜索,压缩是非常耗时的。微软总结了一些过去的开发中出现的现象,其中有一条就是,越是新的对象,越是最快被丢弃不再使用。微软根据这个经验在内存回收中引入了Generation的概念,我此处暂时将其翻译成代。托管堆开始的时候是空的,程序启动开始在其中分配对象,这时候的对象就是第0代(Generation 0)对象。如下图:
接下来,到托管堆空间不足,GC进行了第一次回收,剩下的没有被回收的对象就升为第一代,之后再新分配的对象就是第0代(图甲)。再之后GC再进行回收的话只回收第0代,未被回收的第0代升级为第一代,原来的第一代升级为第0代(图乙)。
GC缺省的代(Generation)最高就是2,升级到第二代就不会再升级了。那什么时候GC回收第一,第二代呢?当GC回收完第0代后,发现内存空间还不够,就会回收第一代,回收完第一代,还不够,就回收第二代。
总结:普通无用对象, GC第1次运行就回收,使用了系统资源的无用对象(有析构函数或者override Finalize()的对象)GC要2才能回收。
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值