silverlining

Go Runtime笔记

Posted at — 12月 3, 2019

Go Runtime是go语言运行的基础设施,Runtime的功能:

  1. 协程的创建和调度
  2. 内存分配和回收管理
  3. map,channel,mutex的创建和实现
  4. pprof和race等检测的实现

协程调度

Go的并发模型

Goroutine

线程的实现模型

G-M模型

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/693f6dd1-861e-41d3-a3b5-83f82d877b89/Untitled.png

Go在最初的1.0版本时Goroutine的调度模型为G-M模型:

问题:

G-P-M模型

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/42d02189-cc74-4916-bfb9-b759c973bc3e/Untitled.png

Go在1.1版本后将Goroutinue版本改为了G-P-M模型:

这个模型实现了Work Stealing算法,解决了之前调度存在的问题:

Goroutine基本状态

协程抢占 - sysmon

sysmon是一个特殊的轻量级协程,sysmon对于运行过久的G设置抢占标识,对于过久系统调用的P,进行M和P的分离,防止P被占用过久影响调度。

sysmon调用retake()时把P的gp.stackguard0设置为stackPreempt,导致P中的执行的G在下次函数调用时触发morestack(),morestack()除了检查是否需要扩张栈,同时还检查是否当前协程需要抢占。

内存分配

Go的内存分配

Go的内存分配器在分配对象时,根据对象的大小,分成三类:小对象(小于等于16B)、一般对象(大于16B,小于等于32KB)、大对象(大于32KB)

大体上的分配流程:

垃圾回收

Golang的混合写屏障结合了插入屏障(插入屏障拦截将白色指针插入黑色对象的操作,标记其对应对象为灰色状态)、删除屏障(保护灰色对象到白色对象的路径不会断),防止对象被漏标记。

Golang GC

三色标记

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/2757e142-5cfc-4ae3-b16d-6d146b01ddbf/gc-1.gif

  1. 初始化三个集合:白、灰、黑
  2. 将所有对象放入白色集合
  3. 从根节点开始遍历扫描所有对象,把遍历的对象从白色集合放入灰色集合
  4. 遍历灰色集合,将灰色对象引用的白色对象从白色集合放入灰色集合,再把自身从灰色集合放入黑色集合
  5. 重复 4 直到灰色中无任何对象,所有可达对象都被标记
  6. 通过write-barrier检测对象有变化,重复以上操作
  7. 收集所有白色对象

写屏障

三色标记需要维护不变性条件:黑色对象不能引用无法被灰色对象可达的白色对象。