go语言条件变量 go语言中if语句多个条件( 三 )

根据索引位置找到对象进行标色
尝试存入 gcwork 的缓存中,或全局队列中
无锁队列,for 循环加原子操作实现栈的 push
到这里把灰色对象标黑就完成了 , 又放回灰色集合接着扫下一个指针 。
Go 语言设计与实现 垃圾收集器
Golang三色标记+混合写屏障GC模式全分析
Golang什么时候会触发GCGolang采用了三色标记法来进行垃圾回收go语言条件变量,那么在什么场景下会触发这个回收动作呢?
源码主要位于文件src/runtime/mgc.gogo version 1.16
触发条件从大方面说go语言条件变量,可分为 手动触发 和 系统触发 两种方式 。手动触发一般很少用,主要由开发者通过调用runtime.GC()函数来实现,而对于系统自动触发是运行时根据一些条件判断来进行的,这也正是本文要介绍的内容 。
不管哪种触发方式,底层回收机制是一样的,所以我们先看一下手动触发,根据它来找系统触发的条件 。
可以看到开始执行GC的是gcStart()函数,它有一个gcTrigger参数,是一个触发条件结构体 , 它的结构体也很简单 。
其实在Golang 内部所有的GC都是通过gcStart()函数 , 然后指定一个 gcTrigger的参数来开始的,而手动触发指定的条件值为gcTriggerCycle。gcStart 是一个很复杂的函数,有兴趣的可以看一下源码实现 。
对于kind的值有三种,分别为 gcTriggerHeap 、gcTriggerTime和gcTriggerCycle。
运行时会通过gcTrigger.test()函数来决定是否需要触发GC,只要满足上面基中一个即可 。
到此我们基本明白了这三种触发GC的条件,那么对于系统自动触发这种,Golang 从一个程序的开始到运行 , 它又是如何一步一步监控到这个条件的呢?
其实 runtime 在程序启动时,会在一个初始化函数init()里启用一个forcegchelper()函数,这个函数位于proc.go文件 。
为了减少系统资源占用 , 在forcegchelper函数里会通过goparkunlock()函数主动让自己陷入休眠,以后由sysmon()监控线程根据条件来恢复这个gc goroutine 。
可以看到sysmon()会在一个for语句里一直判断这个 gcTriggerTime这个条件是否满足 , 如果满足的话,会将forcegc.g这个 goroutine 添加到全局队列里进行调度(这里forcegc是一个全局变量) 。
调度器在调度循环runtime.schedule中还可以通过垃圾收集控制器的runtime.gcControllerState.findRunnabledGCWorker获取并执行用于后台标记的任务 。
彻底理解Golang Map 本文目录如下,阅读本文后 , 将一网打尽下面Golang Map相关面试题
Go中的map是一个指针,占用8个字节 , 指向hmap结构体;源码 src/runtime/map.go 中可以看到map的底层结构
每个map的底层结构是hmap,hmap包含若干个结构为bmap的bucket数组 。每个bucket底层都采用链表结构 。接下来,我们来详细看下map的结构
bmap就是我们常说的“桶”,一个桶里面会最多装 8 个 key,这些 key 之所以会落入同一个桶,是因为它们经过哈希计算后,哈希结果是“一类”的,关于key的定位我们在map的查询和插入中详细说明 。在桶内,又会根据 key 计算出来的 hash 值的高 8 位来决定 key 到底落入桶内的哪个位置(一个桶内最多有8个位置) 。
bucket内存数据结构可视化如下:
注意到 key 和 value 是各自放在一起的,并不是key/value/key/value/...这样的形式 。源码里说明这样的好处是在某些情况下可以省略掉 padding字段,节省内存空间 。
当 map 的 key 和 value 都不是指针 , 并且 size 都小于 128 字节的情况下 , 会把 bmap 标记为不含指针,这样可以避免 gc 时扫描整个 hmap 。但是,我们看 bmap 其实有一个 overflow 的字段,是指针类型的,破坏了 bmap 不含指针的设想,这时会把 overflow 移动到 extra 字段来 。

推荐阅读