漫谈.Net中的自动垃圾收集(Garbage Collection)机制

   一直以来,垃圾收集(Garbage Collection)在软件界的名声并不好。很多程式员认为垃圾收集做得不如自己来的直接,高效。这种说法有些时候是对的,一个精心为自己的特定程式设 计定制的内存回收方法,肯定比为任何程式提供垃圾回收性能要高。但那对程式员需要甚高,一个项目下来花在内存回收的设计上的时间和精力是很可观的,而稍有 不慎便会酿成灾难性的错误,技术再高超的程式员负担不起,整个现代软件工业也负担不起。把这样普遍而又繁重的任务交给系统处理,将程式员从中解脱出来专注 于事务逻辑和系统功能的实现,已成为软件业的共识。微软新推出的.Net平台架构便引入了自动垃圾回收机制,本文将周详解剖其中的原理,回答诸如垃圾回收 怎样工作?怎样控制垃圾回收?什么时候需要控制垃圾回收?什么又是垃圾回收不能解决的?等等重要问题,为.Net平台下的系统研发人员提供设计时的参考。
    要 搞清楚.Net 运行时的垃圾回收机制,首先需要搞清楚.Net运行时内存分配的情况。.Net 运行时对受管资源(Managed Resource)采用对象引用的堆式分配(Heap Allocation)方法。这种分配方法大多数时候是很快的。一个实际系统的内存总是有限的,当系统的剩余的可分配的内存资源不多时,.Net 运行时便会“预见”到下面的内存资源将可能不会满足下面的内存分配请求,于是他便会开始执行垃圾回收释放那些系统不再引用的内存资源。.Net垃圾回收器 采用的是一种叫做“标志紧缩”(Mark and Compat)的算法。每当垃圾收集开始,.Net垃圾收集器从运行时现在的根对象(包括全局对象,本地对象,静态对象,CPU寄存器对象),开始寻找那 些被根对象引用的任何对象,这些对象便是在垃圾收集时运行时正在应用的对象,除去这些,其他的受管运行时对象(Managed Runtime Object)便是系统不再使用的对象,于是便能够进行垃圾收集。任何引用的对象被向下拷贝到运行时受管堆(Runtime Managed Heap),同时修改他们的引用指针。需要指出的是,在.Net垃圾收集器移动引用对象和改变引用指针时,系统不能在这些对象上有任何操作,这一点由运行 时的互斥机制来确保,无需程式员干涉。
    遍历现在任何被引对象的耗费往往是巨大的,实际上也不必这样做。一个经验的认识是,当一个对象在内 存中驻留的时间越长,那么他越有可能继续被引用留在内存中。相反,一个对象在内存中驻留时间越短,他越有可能被收集。.Net收集器采用一种称作“代分 ”(Generation Division)的方法来体现这种经验的内存驻留理论。他把受管堆中的对象分成三代(Generations). 第一代是没有经历过垃圾收集驻留在内存中的对象,他们通常是一些局部变量,他们的生命最短。第二代是仅经历过一次垃圾收集仍然驻留在内存中的对象,他们通 常是一些如表单,列表,按钮等生命较短的对象。第三代是经历过两次及两次以上的垃圾收集后仍然驻留在内存中的对象,他们通常是一些应用程式对象,他们往往 要在内存中驻留很长时间。当运行时收集器开始执行垃圾收集时,他首先对第一代对象进行垃圾收集,这通常会释放较大的内存空间,往往会满足下面的内存请求。 假如这一代的收集结果不理想,那么便会对第二代读像进行收集,同样假如还不理想,便进行第三代的垃圾收集。
    .Net垃圾回收机制支持一种 称作终止化(Finalizaion)的概念。这有点类似C++中的析构函数。终止化操作在垃圾收集执行后进行一些非受管资源的清除工作,他在.Net运 行时里有很多限制,往往不被推荐实现。当程式员对一个对象实现了终止器(Finalizer)后,运行时便会将这个对象的引用加入一个称作终止化对象引用 集的链表,作为需要终止化的标志。当垃圾收集开始时,若一个对象不再被引用但他被加入了终止化对象引用集的链表,那么运行时将此对象标志为需要终止化操作 对象。待垃圾收集完成后,终止化线程便会被运行时唤醒执行终止化操作。显然这之后要从终止化对象引用集的链表中将之删去。容易看出来,终止化操作会给系统 带来额外的开销。终止化是通过启用线程机制来实现的,这有一个线程安全的问题。.Net运行时不能确保终止化执行的顺序,也就是说假如对象A有一个指向对 象B的引用,两个对象都有终止化操作,但对象A在终止化操作时并不一定有有效的对象A引用。所以.Net运行时不推荐对对象进行终止化操作,只是在有非受 管资源如数据库的连接,文档的打开等需要严格释放时,才应用终止化操作。
     大多数时候,垃圾收集应该交由.Net运行时来控制,但有些时候,可能需要人为地控制一下垃圾回收操作。例如在操作了一次大规模的对象集合后,我们确信不 再在这些对象上进行任何的操作了,那我们能够强制垃圾回收立即执行,这通过调用System.GC.Collect() 方法即可实现,但频繁的收集会显著地降低系统的性能。更有一种情况,已将一个对象放到了终止化对象引用集的链上了,但假如我们在程式中某些地方已做了终止 化的操作,在那之后便能够通过调用System.GC.SupressFinalize()来将对象的引用从终止化对象引用集链上摘掉,以忽略终止化操 作。始终应该清楚的是,终止化操作的系统负担是很重的。
    综上所述,.Net垃圾回收机制负责回收系统不再使用的受管内存资源,他通过一定 的优化算法来选择收集的对象和时间。程式员只有在释放大量受管资源时能够进行立即强制垃圾收集,在释放非受管资源时采用终止化操作来处理,其他时间将资源 的回收交由.Net垃圾收集起来做。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值