c++经典的垃圾回收算法介绍

100 篇文章 8 订阅
20 篇文章 0 订阅

我们知道c++程序设计里面的内存分配有三种方法:

1.即全局变量和静态变量,这些都是存储在静态存储区,生存的周期就是程序运行的周期当程序结束,才释放这些存储空间。

2.函数内部的局部变量,这些都是在栈上分配,生存周期是该变量所在的函数的运行周期,函数调用结束,这些存储空间自动释放。

3.动态分配存储空间,在c语言里面我们是通过malloc,free来完成动态存储分配与释放,在c++里是通过new和delete来完成分配和释

放存储空间的,生存周期是由new和delete来决定的。

虽然c++没有和Java样的垃圾回收机制,但是实际上也是有垃圾回收算法的,下面加以介绍。


1.引用计数算法

引用计数(Reference Counting)算法是每个对象计算指向它的指针的数量,当有一个指针指向自己时计数值加1;当删除一个指向

自己的指针时,计数值减1,如果计数值减为0,说明已经不存在指向该对象的指针了,所以它可以被安全的销毁了。这实际上就是

对应“引用计数型智慧指针”(reference-counting smart pointer RCSP)

优点:

1.在内存管理的开销分布于整个应用程序运行期间,非常的“平滑”,无需挂起应用程序的运行来做垃圾回收;

2.空间上的引用局部性比较好,当某个对象的引用计数值变为0时,系统无需访问位于堆中其他页面的单元,而后面我们将要看到的

几种垃圾回收算法在回收前都回遍历所有的存活单元,这可能会引起换页(Paging)操作;

3.提供了一种类似于栈分配的方式,废弃即回收,后面的几种垃圾回收算法在对象废弃后,都会存活一段时间,才会被回收;

缺点:

1.首先能看到的一点是时间上的开销,每次在对象创建或者释放时,都要计算引用计数值,这会引起一些额外的开销;

2.第二是空间上的开销,由于每个对象要保持自己被引用的数量,必须付出额外的空间来存放引用计数值;

3.最大的缺点就在于它无法处理环形引用;

在编程语言Python中,使用也是引用计数算法,当对象的引用计数值为0时,将会调用__del__函数,至于为什么Python要选用引用

计数算法,可能Python作为脚本语言,经常要与C/C++这些语言交互,而使用引用计数算法可以避免改变对象在内存中的位置,而

Python为了解决环形引用问题,也引入gc模块,所以本质上Python的GC的方案是混合引用计数和跟踪(后面要讲的三个算法)两种垃圾回收机制。

2.标记-清除算法

标记-清除(Mark-Sweep)算法依赖于对所有存活对象进行一次全局遍历来确定哪些对象可以回收,遍历的过程从根出发,找到所

有可达对象,除此之外,其它不可达的对象就是垃圾对象,可被回收。整个过程分为两个阶段:标记阶段找到所有存活对象;清除阶段清除所有垃圾对象。

优点:

1.可以非常自然的处理环形引用问题;

2.在创建对象和销毁对象时时少了操作引用计数值的开销;

缺点:

1.是一种“停止-启动”算法,在垃圾回收器运行过程中,应用程序必须暂时停止,所以对于它的研究如何减少它的停顿时间,而分代式

垃圾收集器就是为了减少它的停顿时间;

2.记-清除算法在标记阶段需要遍历所有的存活对象,会造成一定的开销,在清除阶段,清除垃圾对象后会造成大量的内存碎片。

3.标记-缩并算法

标记-缩并算法是为了解决内存碎片问题而产生的一种算法。它的整个过程可以描述为:标记所有的存活对象;通过重新调整存活对

象位置来缩并对象图;更新指向被移动了位置的对象的指针。标记-压缩算法最大的难点在于如何选择所使用的压缩算法,如果压缩

算法选择不好,将会导致极大的程序性能问题,如导致Cache命中率低等。一般来说,根据压缩后对象的位置不同,压缩算法可以

分为以下三种:

1. 任意:移动对象时不考虑它们原来的次序,也不考虑它们之间是否有互相引用的关系;

2. 线性:尽可能的将原来的对象和它所指向的对象放在相邻位置上,这样可以达到更好的空间局部性;

3. 滑动:将对象“滑动”到堆的一端,把存活对象之间的自由单元“挤出去”,从而维持了分配时的原始次序;

4.节点拷贝算法

节点拷贝算法是把整个堆分成两个半区(From,To), GC的过程其实就是把存活对象从一个半区From拷贝到另外一个半区To的过

程,而在下一次回收时,两个半区再互换角色。在移动结束后,再更新对象的指针引用,节点拷贝算法由于在拷贝过程中,就可以

进行内存整理,所以不会再有内存碎片的问题,同时也不需要再专门做一次内存压缩,而它最大的缺点在于需要双倍的空间

5.小结

本文介绍了四种经典的垃圾回收算法,其中后三种经常称之为跟踪垃圾回收,因为引用计数算法能够平滑的进行垃圾回收,而不会

出现“停止”现象,经常出现于一些实时系统中,但它无法解决环形问题;而基于跟踪的垃圾回收机制,在每一次垃圾回收过程中,要

遍历或者复制所有的存活对象,这是一个非常耗时的工作,一种好的解决方案就是对堆上的对象进行分区,对不同区域的对象使用

不同的垃圾回收算法,分代式垃圾回收器正是其中一种,CLR和JVM中都采用了分代式垃圾回收机制。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值