上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
3.3.2 启动
根据相关条件,分成几种执行方式。
// mgc.go const ( gcBackgroundMode gcMode = iota // concurrent GC and sweep gcForceMode // stop-the-world GC now, concurrent sweep gcForceBlockMode // stop-the-world GC now and STW sweep (forced by user) )
进入标记前,有一系列准备工作。
// mgc.go func gcStart(trigger gcTrigger) { // 等待上次回收周期的清理操作结束。 for trigger.test() && sweepone() != ^uintptr(0) { sweep.nbgsweep++ } // 可能有多个线程检查到触发条件。 // 加锁,并再次执行条件检查,使多余的触发提前退出。 semacquire(&work.startSema) if !trigger.test() { semrelease(&work.startSema) return } // 确认是否手工 runtime.GC 调用。 work.userForced = trigger.kind == gcTriggerCycle // 处理 GODEBUG gcstoptheword 设置。 mode := gcBackgroundMode if debug.gcstoptheworld == 1 { mode = gcForceMode } else if debug.gcstoptheworld == 2 { mode = gcForceBlockMode } // 准备 StopTheWorld。 semacquire(&worldsema) // 创建标记工人。 gcBgMarkStartWorkers() // 重置标记状态。 systemstack(gcResetMarkState) // STW! systemstack(stopTheWorldWithSema) // 确保前次清理结束。 systemstack(func() { finishsweep_m() }) // 清除 sync.Pool、sudog 等缓存。 clearpools() // 累加周期计数,准备工作。 work.cycles++ // 控制器本次周期开始。 gcController.startCycle() work.heapGoal = memstats.next_gc // 进入并发标记阶段。(写屏障启用) setGCPhase(_GCmark) // 准备根对象等。 gcBgMarkPrepare() gcMarkRootPrepare() // 微小对象分配块被 cache 持有,所以直接加入灰色队列。 gcMarkTinyAllocs() // 允许黑化标记。(辅助回收启用) atomic.Store(&gcBlackenEnabled, 1) // 解除 STW,以便 schedule 开启 Worker 进行回收作业。 systemstack(func() { now = startTheWorldWithSema() }) // 非并发模式下,当前 goroutine 将被暂停。 if mode != gcBackgroundMode { Gosched() } // 释放锁,使得其他线程可以进入。 semrelease(&work.startSema) }
设置阶段标记时,会按需启用写屏障设置。
// mgc.go func setGCPhase(x uint32) { atomic.Store(&gcphase, x) writeBarrier.needed = gcphase == _GCmark || gcphase == _GCmarktermination writeBarrier.enabled = writeBarrier.needed || writeBarrier.cgo }
gcBgMarkStartWorkers
为每个 P 创建一个专职标记的工人(worker goroutine)。
仅表示该 P 可以具备回收能力,是否参加要看 startCycle 里的数量设置。
// mgc.go // gcBgMarkStartWorkers prepares background mark worker goroutines. // These goroutines will not run until the mark phase, ... func gcBgMarkStartWorkers() { for _, p := range allp { if p.gcBgMarkWorker == 0 { go gcBgMarkWorker(p) // 等新工人准备好,再创建下一个。 notetsleepg(&work.bgMarkReady, -1) noteclear(&work.bgMarkReady) } } }
func gcBgMarkWorker(_p_ *p) { park.attach.set(_p_) // 准备完毕,可以创建下一个。 notewakeup(&work.bgMarkReady) for { // // gopark 执行 fn,如果函数返回值为 true 则休眠。 gopark(func(g *g, parkp unsafe.Pointer) bool { park := (*parkInfo)(parkp) if park.attach != 0 { // 将工人(worker goroutine)关联到 P。 p := park.attach.ptr() park.attach.set(nil) if !p.gcBgMarkWorker.cas(0, guintptr(unsafe.Pointer(g))) { return false } } return true }, unsafe.Pointer(park), ...) ... 执行标记任务 ... } }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论