dotnet学习笔记五 - 无用资源回收之二

l         Fina li ze

在上一篇文章中我分配使用资源一共五步,我们已经知道了GC是如何释放无用对象的内存了。但是它怎么实现第四步清空资源使用状态、释放利用到的一些非内存的系统资源呢?.NET引入了Fina li ze来完成这个任务。

GC在无用单元回收时一旦发现某个对象有Fina li ze方法,便调用它。所以我们的Fina li ze方法一定要尽量少做事情,以提高内存回收的速度。另外,在Fina li ze方法中不要有任何的线程同步等操作,以防止GC线程被挂起。

我们可以用两种方法来写自己的Fina li ze方法。一种就是显示的实现,如下面的代码:

代码1

pub li c class SomeClass

{

   pub li c SomeClass()

   {

   }

 

   protected override void Fina li ze()

   {

      Console.WriteLine(“Fina li zing…”);

   }

}

使用这种方法时要注意一点,.NET不会帮你做调用基类的Fina li ze方法。如果需要调用基类的Fina li ze方法,需要显示的调用。如下面代码:

代码2

pub li c class SomeClass

{

   pub li c SomeClass()

   {

   }

 

   protected override void Fina li ze()

   {

      Console.WriteLine(“Fina li zing…”);

      base.Fina li ze(); // 调用基类Fina li ze方法

   }

}

另外一种方法就是析构函数。C#中的析构函数不同于C++。我们看下面的代码:

代码3

pub li c class SomeClass

{

   pub li c SomeClass()

   {

   }

 

   ~SomeClass()

   {

      Console.WriteLine(“Fina li zing…”);

   }

}

它等同于代码2

使用Fina li ze方法要特别小心。因为使用Fina li ze方法的对象要比普通的对象花时间;GC也要花更多的时间来回收。而且CLR并不能保证调用Fina li ze的顺序,所以如果对象间有关联(比如一个成员变量先被Fina li ze了,如果在Fina li ze方法里还使用它,就会出错),就会更麻烦。

GC是如何实现Fina li ze的呢?GC维护了两个队列,Fina li zation队列和Freachable队列。在托管堆分配对象的时候,GC如果发现这个对象实现了一个Fina li ze方法,就把它加到Fina li zation队列。如图:

当托管堆的内存不足的时候,GC开始对堆进行回收。GC回收一个对象前,先检查Fina li zation队列中是否有这个对象的指针,如果有,就将其放入Freachable队列。Freachable队列被认为是根(root)的一部分,所以GC不会对其作回收。GC第一次回收后,堆如下图:

对象G和对象E不在根的范围之内,被回收。对象F和对象C由于需要Fina li ze被放入到Freachable队列,这个队列被认为是根的一部分,所以这是对象F和对象C就复活了,没有被GC回收。Freachable队列中的对象的Fina li ze方法被一个特殊的线程执行。这个线程平时处于非活动状态,一旦Freachable队列不再为空,它就醒过来,一一执行这个队列中对象中的Fina li ze方法。执行过后如下图:

这时对象F和对象C不再是根的一部分,如果此时GC进行回收,将会被认作无用对象进行回收,回收后如下图:

上面简单描述了Fina li ze作用及其内部的工作原理。下面来说一下Generation

l         Generation

每次都对整个对进行搜索,压缩是非常耗时的。微软总结了一些过去的开发中出现的现象,其中有一条就是,越是新的对象,越是最快被丢弃不再使用。微软根据这个经验在内存回收中引入了Generation的概念,我此处暂时将其翻译成代。托管堆开始的时候是空的,程序启动开始在其中分配对象,这时候的对象就是第0(Generation 0)对象。如下图:

接下来,到托管堆空间不足,GC进行了第一次回收,剩下的没有被回收的对象就升为第一代,之后再新分配的对象就是第0代(图甲)。再之后GC再进行回收的话只回收第0代,未被回收的第0代升级为第一代,原来的第一代升级为第0代(图乙)。

GC缺省的代(Generation)最高就是2,升级到第二代就不会再升级了。那什么时候GC回收第一,第二代呢?当GC回收完第0代后,发现内存空间还不够,就会回收第一代,回收完第一代,还不够,就回收第二代。

这一篇也写了不少了,所以下一篇再继续,下一篇写WeakReference和如何在自己的代码中控制GC的动作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值