GC算法

Posted by Liao on 2022-04-21

一、背景知识

  • bbs数据段:全局变量、静态数据
  • 函数栈帧(栈):函数的局部变量、参数、返回值。栈是系统自动分配空间的,例如定义一个var a string;系统会自动在栈上为其开辟空间。
  • 堆:函数内部动态分配的内存,由程序员申请分配和释放。在编译阶段不能确定数据对象的大小、或者对象的生命周期超出了当前所在函数,则不适合分配在栈上,要分配在堆。

分配在堆上的数据需要程序主动释放才可以重新使用,否则会成为垃圾,而垃圾越积越多会消耗系统内存。

手动垃圾回收:c、c++等语言需要程序手动释放不再需要的、分配在堆上的数据。一旦释放得早,后续对该数据的访问会出错,因为被释放的内存可能已经被清空,或者重新分配,甚至已经还给OS,这就是悬挂指针问题;但若忘记释放,就会一直占用内存,出现内存泄露

自动垃圾回收:由运行时识别不再有用的数据,并释放它们占用的内存。

二、种类

2.1 三色标记法(Go实现的垃圾回收器)

三色标记法(追踪式回收)是基于**标记-清扫算法 (Mark - Sweep) **的思想:程序中用得到的数据是从数据段追踪得到的数据(可达性近似等于存活性),可以以它们为根结点进行追踪,能追中到的数据进行标记,追踪不到的对象就是垃圾,进行回收。

缺点:

  • 容易造成内存碎片化

  • 避免存活对象误判为垃圾对象的情况,例如刚才识别为垃圾的对象被用户修改了,后面还需要用。这种情况通过强弱三色不变式解决

2.2 引用计数(PHP)

程序运行时会对对象进行计数(当变量a对变量b进行引用表示有依赖)。当技术为0时表示这个对象不再有用,可以回收它占用的内存。

缺点:高频率更新引用次数会造成不小的系统开销,而且容易造成循环引用

2.3 复制式回收(追踪式回收)

  • 把堆内存划分为两个相等的空间,From和To。程序执行时,使用From空间。
  • 垃圾回收执行时,会扫描From空间,把能追踪到的数据复制到To空间。
  • 当所有有用的数据都复制到To空间后,把From和To的角色交换

优缺点:复制式回收不会带来碎片化问题,但只有一半的堆内存可以被使用,因此通常搭配其它垃圾回收算法(如分代回收)一起使用,只在一部分堆内存中使用复制式回收。

2.4 分代回收(追踪式回收)

  • 该垃圾回收算法基于弱分代假说:大部分对象都在年轻时死亡。

    换言之,新生代对象成为垃圾的概率高于老年代对象,故可把数据分为新生代和老年代,降低老年代垃圾回收的频率,不用每次都处理所有数据,提升垃圾回收效率。

  • 新生代和老年代可以分别采取不同的垃圾回收策略,进一步提升回收效率并减少开销。