常见的 GC 模式
常见的 GC 模式
- 引用计数(reference counting)每个对象维护一个引用计数器,当引用该对象的对象被销毁或者更新的时候,被引用对象的引用计数器自动减 1,当被应用的对象被创建,或者赋值给其他对象时,引用 +1,引用为 0 的时候回收,思路简单,但是频繁更新引用计数器降低性能,存在循环以引用(php,Python所使用的)
- 标记清除(mark and sweep)就是 golang 所使用的,从根变量来时遍历所有被引用对象,标记之后进行清除操作,对未标记对象进行回收,缺点:每次垃圾回收的时候都会暂停所有的正常运行的代码,系统的响应能力会大大降低,各种 mark&swamp 变种(三色标记法),缓解性能问题。
- 分代搜集(generation)jvm 就使用的分代回收的思路。在面向对象编程语言中,绝大多数对象的生命周期都非常短。分代收集的基本思想是,将堆划分为两个或多个称为代(generation)的空间。新创建的对象存放在称为新生代(young generation)中(一般来说,新生代的大小会比 老年代小很多),随着垃圾回收的重复执行,生命周期较长的对象会被提升(promotion)到老年代中(这里用到了一个分类的思路,这个是也是科学思考的一个基本思路)。
因此,新生代垃圾回收和老年代垃圾回收两种不同的垃圾回收方式应运而生(先分类,之后再对症下药),分别用于对各自空间中的对象执行垃圾回收。新生代垃圾回收的速度非常快,比老年代快几个数量级,即使新生代垃圾回收的频率更高,执行效率也仍然比老年代垃圾回收强,这是因为大多数对象的生命周期都很短,根本无需提升到老年代。
golang 中的 gc 通常是如何工作的
golang 中的 gc 基本上是标记清除的思路:
在内存堆中(由于有的时候管理内存页的时候要用到堆的数据结构,所以称为堆内存)存储着有一系列的对象,这些对象可能会与其他对象有关联(references between these objects) a tracing garbage collector 会在某一个时间点上停止原本正在运行的程序,之后它会扫描 runtim e已经知道的的 object 集合(already known set of objects),通常它们是存在于 stack 中的全局变量以及各种对象。gc 会对这些对象进行标记,将这些对象的状态标记为可达,从中找出所有的,从当前的这些对象可以达到其他地方的对象的 reference,并且将这些对象也标记为可达的对象,这个步骤被称为 mark phase,即标记阶段,这一步的主要目的是用于获取这些对象的状态信息。
一旦将所有的这些对象都扫描完,gc 就会获取到所有的无法 reach 的对象(状态为 unreachable 的对象),并且将它们回收,这一步称为 sweep phase,即是清扫阶段。
gc 仅仅搜集那些未被标记为可达(reachable)的对象。如果 gc 没有识别出一个 reference,最后有可能会将一个仍然在使用的对象给回收掉,就引起了程序运行错误。
可以看到主要的三个步骤:扫描,回收,清扫。
感觉比起其他的语言,golang 中的垃圾回收模型还是相对简单的。
转载 https://blog.csdn.net/u010649766/article/details/80582153