go运行库-调度器(一)

之前写过一段时间java,java vm的gc机制几乎是准高级java程序员的必须了解的东西。虽然一直没报以重视,但最近在看完golang的hashmap机制之后,觉得有必要深入了解下golang的gc机制。

gc是现代语言的标配,因为内存日益廉价,回收内存的时机允许一定的异步导致gc这个方案的诞生,当然,gc作为从业务逻辑中分离出内存管理的部分(并加入跨平台的特征),解放了业务逻辑的开发。但从某种意义上讲并没有解放程序员,因为程序员需要深入了解这部分内容才能针对特定语言运行时内存状况有把控能力。

本以为gc是相对独立的一套算法的组合,看起来不会依赖过多。但实际阅读过程中还是遇到很多难理解的非算法相关内容,比如g p m,这些对象的出现增加了阅读gc的辐射范围。痛苦挣扎后,阅读目标逐渐转向golang运行库,支撑业务运行的透明层。

src/runtime目录下的文件是golang运行库的实现,也可以参考《程序员自我修养》中的个别章节对于运行库的描述,之前对于语言的使用都是浮于表面,例如,golang据说以多核并发运行效率的提升为核心目标,那么java在多核的情况下运行效果怎么样,你不能单纯的写两个程序在自己电脑上跑下,就说xx比xx好,并从cpu和内存角度瞎评论一番,这中情景的分析需要更深一层,推敲需要更严谨。

上面的描述只是golang runtime代码阅读的开始过程,下面加一段关于go关键字的理解。

go a(arg int) 使用起来比较简单,映射到运行库时,会比较直观的调用newproc1方法申请一个新的G,把G加入到某个P的调度队列中。

newproc1方法中获取G调用了gfget方法,这里多说一句,作者对于gfget的命名思路:g-goroutine f-空闲 get-操作,同类的函数还有gfputgfpurge,用于操作当前P和全局的空闲G列表。

gfget方法,也会涉及到一些不熟悉的名词,类似schedschedlink这些都是什么?

  • sched全局变量,存储全局空闲G链表(这里仅关心这个)
  • schedlinkG的属性,用于指向下一个G,这个命名导致需要通过它的使用方式推敲具体功用

申请新的G时整体策略:先从本地P的空闲G列表(gfree)获取如果有,直接在这个G对象基础之上申请stack空间即可;当gfree空时,如果sched中空闲列表非空,就尝试迁移sched中的Ggfree中。这里注意本地和全局链表都为空时,会返回nil有个细节的点没有搞懂,sched中存在gfreeStackgfreeNoStack两种类型的G,这两种在gc时会有迁移的地方,但具体为什么出现这两种情况的stack,需要后续研究下golang中stack的使用

本地的空闲链表不能无限增长,所以在gfput时,大小为64时,需要迁移到全局链表中一部分。

未完待续。。。

newprocgetcallerpc(unsafe.Pointer(&siz))的调用和该方法内部的解释不一致,方法注释中the argp must be a pointer to the caller's first function argument,但实际中使用的是参数的字节数。pc是程序计数器,用于记录调用当前方法的地址,方法执行完成后会返回到该地址继续调用方的后续逻辑。

sysmon是相对独立意图比较明确的一部分逻辑,和平时设计服务一样,服务内部会有定时检查的任务,防止系统出现问题。同时每个服务的这部分逻辑,也会展现它上级服务需要关注的点。资源消耗,心跳操作,系统内部队列阻塞探测和解决。下面描述小sysmon

  • 变量delay以2倍数值增长,直到超过10ms或者本次循环抢占到任何goroutine,delay的这种增长趋势不懂,可能是相同速度的循环会浪费资源,在google的大量测试发现这种增长方式比较合理,是实践的结果,注意抢占到goroutine作为sysmon循环的重新开始信号。
  • if debug.schedtrace <= 0 && (sched.gcwaiting != 0 || atomic.Load(&sched.npidle) == uint32(gomaxprocs)),在非debug情况下,如果gc没有将要执行或者空闲p的数量和可启动最大系统thread相同,这个时候表示系统没有资源需要清理或者给gc留出一点资源。
  • netpoll这个是获取goroutine一种方式,待推敲
  • retake可以防止goroutine进行的系统调用时间过长或者本身运行时间过长
  • forcegc是一个g的链表,需要强制回收资源的g会链接到这个上面,具体场景,遇到时再看
  • mheap堆清理
  • schedtrace运行go程序时传入,可以打印当前调度情况,参考
go运行库-调度器(一)
Share this