垃圾回收的算法的选择!?

        最近在看《C++编程艺术》,这本说讲的很深刻,讲到了垃圾回收算法!看着很是爽!就将一个信息摘录出来,供大家学习!

选择垃圾回收的算法:

        在为C++实现垃圾回收器之前,有必要确定垃圾回收使用的算法。在这里介绍三种典型的方法:引用计数、标记并清除、复制。在确定选择哪种方法的同时,我们先来浏览一下这三种算法:

引用计数:

       在引用计数中,每一块动态分配的内存都与一个引用计数有关。这个计数在每次对内存的引用增加的时候增加1,在取消对内存的引用是减1.用C++的术语来说,这意味着每次将一个指针指向一块已分配内存的时候,与内存相关的引用计数增加1.当这个指针指向其他位置的时候,引用计数减1.当引用计数下降为0的时候,内存不再被使用,从而可以释放。

      引用计数的最大优点是其简单性----易于理解并实现。另外,它的位置不受堆结构的影响,因为引用计数不依赖于对象的物理位置。引用计数增加了每个指针操作的开销,但是回收阶段的开销相对较低。其主要的缺点是循环的引用阻止了其他不再使用的内存的释放。当两个对象互相指向对方的时候(无论是直接的还是间接的),就会发生循环引用。在此情况下,对象的引用计数永不为0.为了解决循环引用的问题,设计了一些解决方案,但是这些方案都会增加复杂程度和开销。


标记并清除:

       标记并清除涉及到两个阶段。在第一个阶段,堆中的所有对象都被设置为未标记状态。然后,可以由程序变量直接或者间接访问的所有对象都被标记为“正在使用”。在第二个阶段,扫描所有已分配的内存(也就是说,进行了内存的清除),会释放所有未标记的元素。

       标记并清除有两个主要优点:

              首先,他很容易处理循环引用;

              其次,在回收之前,他实际上没有增加运行时开销;

       标记并清除也有两个主要的缺点:

              首先,由于在回收的时候必须扫面整个堆,因此回收垃圾可能会花费较多的时间。因此,对于某次额程序,垃圾回收可能会导致程序运行效率低下;

              其次,尽管标记并清除在概念上很简单,但是要有效地实现它并非易事;


复制:

        复制算法将自由内存分到两个空间中。一个是活动空间(持有当前的堆),一个是空闲空间。在垃圾回收期间,活动空间中正在使用的对象被确认,并复制到空闲空间中。然后,两个空间的角色反转,空闲空间变为活动空间,活动空间变为空闲空间。提供了复制过程中压缩堆的优点。它的缺点是在某个时刻只允许使用一个的自由内存。


采用哪种算法:

       三种垃圾回收的经典算法都各自的优缺点,好像很难做出选择。然而,考虑前面列举出的限制,就会得出明显的选择:引用计数。最重要的是,引用计数可以很容易地应用与现有的C++动态分配系统上。其次,他可以以一种直接的方式来实现,而不会影响代码。第三,它不需要堆的任何特定的组织或者结构,从而不会影响C++提供的标准分配系统。

       使用引用计数的一个缺点是很难处理循环引用。这对于许多程序而言,并不是一个问题,因为有意的循环引用并不常用,并且可以避免。(即使我们所说的循环,如循环队列,也不一定要用到循环指针引用)。当然,某些情况下需要使用循环引用。也可能建立了循环引用,而您并不知道,特别是使用第三方库的时候。因此,垃圾回收器必须提供某种方法来适度地处理循环引用。

      为了处理循环引用问题,释放任何已经分配的内存。这将确保涉及到循环引用的对象被释放,并且调用他们的析构函数。通常在程序结束的时候,不应该再有已分配的对象,理解这一点很重要。对于涉及到循环引用而不能被释放的对象,这种机制是显示的。


实现垃圾回收器

       为了实现引用计数的垃圾回收器,必须有某种方法来跟踪指向每块动态分配的内存的指针的数量。问题在于,C++没有内建的机制来确保一个对象知道其他的对象何时指向他。

       幸运的是,在此有一个解决方案:可以建立一个新的支持垃圾回收的指针类型。

       为了支持垃圾回收,新的指针类型必须做三件事情:

  1. 它必须为使用中的动态分配的对象维护一个引用计数的链表;
  2. 它必须跟踪所有的指针运算符,每次某个指向一个对象时,都要使这个对象的引用计数增加1,每次某个指针重新指向其他对象的时候,都要使这个对象的引用计数减1;
  3. 它必须回收那些引用计数为0的对象。除了支持垃圾回收之外,这个新指针类型与普通的指针看起来一样;
       垃圾回收指针类型的建立不仅以一种简单的方法实现垃圾回收器,而且还满足不影响原始的C++动态分配系统的限制。当需要垃圾回收的时候,使用支持垃圾回收的指针。当不需要垃圾回收的时候,使用普通的C++指针。因此,这两种类型的指针在同一个程序内都可以使用。

是否使用多线程
       再设计C++的垃圾回收器时,另一个考虑是应该使用单线程还是多线程。也就是,是否应该吧垃圾回收器设计为一个后台进程,在它自己的线程内运行,并且在CPU时间允许是回收垃圾。或者,这个垃圾回收器在使用它的进程的相同线程中运行,当满足某程序条件的时候回收垃圾。这两种方法各有优缺点。
       建立多线程垃圾回收器的主要优点是效率。垃圾可以在CPU空闲时被回收。其缺点是,C++没有提供内建的多线程支持,这意味着威力支持多任务,任何多线程方法都依赖于操作系统是否支持多任务,这使得代码不可移植。
       使用单线程垃圾回收器的主要优点是代码可以移植。在不支持多线程或者支持多线程的代价很高的情况下使用。主要缺点是当垃圾回收发生时,程序的其他部分会停止运行。

何时回收垃圾
       在实现垃圾回收器之前,需要回答一个问题是:什么时候开始垃圾回收?对于多线程的垃圾回收器这不成问题,因为他可以作为后台任务连续运行,并且在CPU空闲的时候回收垃圾。然而对于单线程的垃圾回收器,为了回收垃圾,必须停止运行程序的其他部分。
       实际上,只有在有足够的理由(如内存持续降低)的时候,才会进行垃圾回收。有两个原因使得这样做有意义。首先,通过某种垃圾回收算法,如标记并清除,如果不实际执行回收,就没有办法知道不在使用那块内存。其次,回收垃圾是一个耗时的过程,在不需要的时候不应该执行它。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值