Go学习笔记(day8) | 青训营笔记

107 阅读5分钟

这是我参与「第五届青训营」伴学笔记创作活动的第8天

笨人纯小白,笔记包括一些上课学到的知识和课外总结的内容,如有错误请指正!

十一、Golang内存管理(三:垃圾回收GC)

11.1 垃圾回收算法

引用计数

对每一个对象维护一个计数器,引用该对象的对象被销毁时,计数器减一,计数器减为0时回收对象,表示没有被引用了。

  • 优点:对象可以很快被回收,不会出现内存耗尽才回收。
  • 缺点:对于循环引用的处理并不友好。

标记清除

根变量开始遍历所有引用的对象,引用对象标记为被引用,没有标记的对象被回收。

  • 优点:解决了引用计数不能很好地处理循环引用的问题。
  • 缺点:GC时需要暂停程序运行。

分代收集

按照对象生命周期长短划分不同的代空间,生命周期长的放入老年代,生命周期短的放入新生代,不同代有不同的回收算法。

  • 优点:回收性能高。
  • 缺点:算法复杂。

Go语言采用的是标记清除法,Go把它称作三色标记法

11.2 根对象

根对象是在垃圾回收的过程中最先被检查的对象,包括:

  • 全局变量:全局变量存在于程序整个生命周期。
  • 协程栈中的对象,或者从栈上逃逸到堆上的对象。
  • 被寄存器中的指针引用的对象。

11.3 三色标记法

三色只是为了方便描述而抽象出来的一种说法,实际上并没有颜色,所说的三种颜色指的是对象的三种状态。

  • 白色:对象未被标记,在mspan中的gcmarkBits成员对应的位为0。
  • 灰色:等待被标记的对象
  • 黑色:对象被标记,在mspan中的gcmarkBits成员对应的位为1。

三色标记的过程

假设根对象为A,内存中存在六个对象,分别是对象1~对象6,根对象A引用了对象2,而对象2引用了对象4。

第一步,初始所有对象都标记为白色。

第二步,从根对象A对其引用的对象进行扫描,扫描到的对象(对象2)标记为灰色。

第三步,将灰色对象(对象2)标记为黑色,把灰色对象(对象2)标记为黑色的同时,扫描其(对象2)引用的对象(对象4)标记为灰色。

第四步,将灰色对象(对象4)标记为黑色,同时扫描(对象4)其引用的对象,发现没有引用其他对象了,此时不存在灰色对象了。而对象1、对象3、对象5、对象6都是白色,对象2、对象4为黑色,当不存在灰色对象时表明标记过程结束,那么所有白色对象会被回收,黑色对象保留

11.4 STW

STW全称为stop the world,意思是暂停程序的运行,在垃圾回收的过程中,如果不暂停程序的运行,指针传递会引起内存引用关系变化,如果错误的回收了还在使用的内存,带来的结果可能是灾难性的。例如下图中,A、B、C、D、E、F都被标记为黑色,而G、H为白色,那么G、H将会被回收,如果没有STW,此时程序继续运行,黑色对象突然又引用了G、H,而扫描过程已经结束了,那么就会错误的回收G、H这两个还在使用的对象。 image.png

因此在进行垃圾回收时,需要暂停程序的运行,专心做垃圾回收,等待垃圾回收结束后再恢复程序运行。

11.5 混合屏障

由于STW对程序的执行影响较大,对于一些应用是不可接受的,特别是WEB应用,所以Go也不断地在优化GC,提出了混合屏障,使得程序和GC同时运行。

删除屏障

灰色对象B引用了对象C,如下图: image.png GC扫描的过程,程序继续执行,此时程序移除了灰色对象B对白色对象C的引用,如下图: image.png 程序继续执行,此时程序添加了黑色对象E对白色对象C的引用,如下图: image.png GC扫描的过程只会扫描根对象和灰色对象的引用,而不会扫描黑色对象的引用,所以上述情况会导致最终对象C被错误清除。

因此出现了删除屏障,删除屏障就是在GC扫描的过程中,对于引用被移除的对象(上图中的C对象),会立即置为灰色,保证其不会被错误清除

所以上述过程变为了: image.png 移除了B对象对C对象的引用: image.png 删除屏障起作用,将被移除引用的C对象置灰: image.png 程序添加了黑色对象E对白色对象C的引用: image.png 最终保证了C对象不会被错误回收。

插入屏障

删除屏障保证了移除引用时,对象不会被错误清除,但是并不能保证所有情况下对象都不会被误回收。例如:

GC扫描的过程中,C对象不存在被谁引用,等待被删除: image.png GC扫描的过程中,程序继续执行,让黑色对象E新增了一个对C对象的引用: image.png 所以C对象最后还是会被回收,于是就出现了插入屏障,插入屏障就是在GC扫描的过程中,对于新增引用的对象(上图中的C对象),会立即置为灰色,保证其不会被错误清除。

所以上述过程变为了: image.png 新增引用,插入屏障起作用,对象C立即标记成灰色: image.png 插入屏障最终保证了C对象不会被错误回收。

混合屏障

Go语言GC采用的是混合屏障来保证GC过程中对象不会被错误的回收,其实混合屏障就是两种写屏障——插入屏障和删除屏障一起使用。