GO语言-GC

木工007 · · 678 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

引言

        垃圾回收机制是高级语言常见的一类内存资源管理方式,C/C++这类语言内存分配及回收很大的主动权在调用者,gc机制较弱;像JAVA、PYTHON及后来的GOLANG都添加了GC机制来减少编程人员的内存管理压力。但于此同时也带来了gc效率问题,接下来我们看下常见的GC方式。

GC算法

        常见GC方式有引用计数(reference counting)、标记-清除(mark & sweep)、节点复制(Copying Garbage Collection),分代收集(Generational Garbage Collection)。

    引用计数

        引用计数算是在gc算法中最简单,也是最直接的gc算法。引用计数是在对象赋值操作时进行额外的清除操作,赋值时减少右值对象所有域的引用计数,计数为0立即进行垃圾处理,不需要STW。但对于环形数据问题(循环引用)无法回收,导致内存泄露。

    标记-清除

        标记-清除根据字面意思已经很明显了,分两步走:

            第一,标记对象

            第二,清除对象(残忍)

        标记还在使用的对象,清除不用的对象,回收资源。那程序在运行时可能改变对象,所以STW(STOP THE WORLD)上场。意思就是有那么一瞬间,程序是暂停运行的。待清除完不用的对象然后继续运行原来的程序。这样的运行原理导致程序可能出现走走停停(可能对你无感知),这个标记清除的时机怎么确定呢???!!!

    节点复制

          copy gc算法是分配A和B空间(学名Allocation Space和Survivor Space),程序在空间A生成对象时,如果没有空间可用则触发一次GC,遍历A空间全部变量是否存活(使用),如果存活状态则复制到B空间,然后清除A空间(此时全是垃圾变量),然后再讲B空间变量移动到A空间。

    分代收集

        分代收集算法主要考虑对象的生命周期,大部分对象的生命周期较短,小部分对象的生命周期较长(2-8定律?)。尽可能的减少gc扫描生命周期较长的对象来提高gc效率。将新创建的对象归入新生代,随着扫描的进行将新生代剩余对象归入老生代,扫描主要在新生代进行,这类扫描叫小扫描。但老生代对象也可能耗尽生命,所以每隔段时间还需要一次对老生代的扫描,称之为大扫描。在新生代扫描时,新生代对象可能只被老生代对象引用,不能将其标记为“可回收”,需要引入记录集记录该情况,即写屏障机制(write barrier)。

GO语言GC机制及演进

    STW-标记-清除(V1.3以前)

        go开始GC版本很暴力,暂停整个程序然后执行标记清除,然后再恢复运行。这对高并发低延迟要求的程序来说应该是灾难了(反正我没经历这一版);当时的解决方案是什么呢,猜,也是像C/C++一样自行控制内存,减少gc次数来减少这种情况的发生吧。

    标记-清除(V1.3)

        如果在了解stw-标记-清除原理的情况下优化该gc方式,你会想到什么呢?

        1.3版本聪明的程序员们又开始“想办法”了,标记阶段必须暂停程序,但清除阶段没必要暂停程序逻辑,两者可以并行进行。so该版本优化了标记-清除的gc方式,减少程序暂停时间来减少“卡顿”提升GC效率。但该方法只是优化(提升还是很多的,go team自己的说法是减少了50%-70%的暂停时间),没有从根本上解决问题,要想继续提升还得继续“想”!

    三色标记(V1.5)

        三色标记是对标记清除的进一步改进,v1.3版本改进了清除逻辑与业务逻辑的并发。标记过程能不能也不停止程序运行呢?!答案是肯定的,只是引入了更多机制(写屏障(write barrier) )。开始都为白色,标记可达对象为灰色,然后被灰色对象引用的对象为灰色,此时标记原来的灰色对象为黑色,最终白色对象被清除。如果此时有新对象生成就标记为灰色,如果引用了白色对象则触发写屏障机制来处理该白色对象。这样就能与用户的业务逻辑并发了。

    混合写屏障(V1.8)

        Golang 1.7 之前的 write barrier 使用的经典的 Dijkstra-style insertion write barrier [Dijkstra ‘78], STW 的主要耗时就在 stack re-scan 的过程。自 1.8 之后采用一种混合的 write barrier 方式 (Yuasa-style deletion write barrier [Yuasa ‘90] 和 Dijkstra-style insertion write barrier [Dijkstra ‘78])来避免 re-scan。

总结

        GOLANG的垃圾回收优化是不断进行的,从最初的集中式gc(stw)到后来分散处理gc(与业务代码并行),用户感知上削弱了但不代表总的gc时间减少。所以还需尽可能控制GC触发提高效率。至于何时触发GC及怎么减少代码GC次数,且听下章分解吧-.-

引用

    Golang 垃圾回收剖析


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:木工007

查看原文:GO语言-GC

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

678 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传