清扫
func gcSweep(mode gcMode) {...//阻塞式if !_ConcurrentSweep || mode == gcForceBlockMode {// Special case synchronous sweep....// Sweep all spans eagerly.for sweepone() != ^uintptr(0) {sweep.npausesweep++}// Do an additional mProf_GC, because all 'free' events are now real as well.mProf_GC()mProf_GC()return}// 并行式// Background sweep.lock(&sweep.lock)if sweep.parked {sweep.parked = falseready(sweep.g, 0, true)}unlock(&sweep.lock)}
并行式清扫,在 GC 初始化的时候就会启动 bgsweep(),然后在后台一直循环
func bgsweep(c chan int) {sweep.g = getg()lock(&sweep.lock)sweep.parked = truec <- 1goparkunlock(&sweep.lock, "GC sweep wait", traceEvGoBlock, 1)for {for gosweepone() != ^uintptr(0) {sweep.nbgsweep++Gosched()}lock(&sweep.lock)if !gosweepdone() {// This can happen if a GC runs between// gosweepone returning ^0 above// and the lock being acquired.unlock(&sweep.lock)continue}sweep.parked = truegoparkunlock(&sweep.lock, "GC sweep wait", traceEvGoBlock, 1)}}func gosweepone() uintptr {var ret uintptrsystemstack(func() {ret = sweepone()})return ret}
不管是阻塞式还是并行式,都是通过 sweepone()函数来做清扫工作的.内存管理都是基于 span 的,mheap 是一个全局的变量,所有分配的对象都会记录在 mheap 中。在标记的时候,我们只要找到对对象对应的 span 进行标记,清扫的时候扫描 span,没有标记的 span 就可以回收了。
// sweeps one span// returns number of pages returned to heap, or ^uintptr(0) if there is nothing to sweepfunc sweepone() uintptr {...for {s := mheap_.sweepSpans[1-sg/2%2].pop()...if !s.sweep(false) {// Span is still in-use, so this returned no// pages to the heap and the span needs to// move to the swept in-use list.npages = 0}}}// Sweep frees or collects finalizers for blocks not marked in the mark phase.// It clears the mark bits in preparation for the next GC round.// Returns true if the span was returned to heap.// If preserve=true, don't return it to heap nor relink in MCentral lists;// caller takes care of it.func (s *mspan) sweep(preserve bool) bool {...}