golang 源码剖析(4): 垃圾回收

#基本概念

三色标记和写屏障

  • 起初所有的对象都是白色
  • 扫描所有的可达对象,标记为灰色,放入待处理队列
  • 从队列中提取灰色对象,将其引用的对象标记成灰色放入队列,自身标记为黑色
  • 写屏障监视对象内存修改,重新标色或者放回队列.
    当完成全部的扫描和标记工作后,剩余的只有白色和黑色两种,分别代表待回收和活跃对象,清晰操作只需将白色对象内存回收即可。

流程

可分为以下几步:

  1. 扫描
    a. 设置STW(stop the world,暂停用户进程) . 这将导致所有的Ps都到GC的安全点.在这里无法做内存操作.
    b. 扫描所有未扫描的spans, 只有当gc被迫提前是才会有未扫描的spans

  2. 执行mark阶段
    a. 将gc的阶段从_GCoff改为_GCmark,开启写屏障(write barrier),开启辅助gc,并且将root标记工作入队. 可能在所有的Ps开启写屏障之前不会做扫描操作,写屏障使用SWT实现.
    b. Start the world. 因为调度器早就运行标记worker和辅助协程执行了部分的分配,在这里GC标记工作已经完成. 写屏障将指针引用的改变和新的引用指针都置为灰色(shade). 新申请的对象会直接标记为黑色
    c. gc开始root标记工作. 包括扫描所有的栈,置灰所有全局变量和heap上的指针和非heap上的运行时数据结构。每扫描一个goroutine栈就暂停一个goroutine,将栈上所有指针都置为灰色,然后将goroutine恢复.
    d. gc 从灰色的work queue中放出灰色对象,扫描每个灰色对象变成灰色,并且置灰指向它的指针(引用它的对象)
    e. 由于gc工作在local cache上处理, 当没有多余的root标记工作或者灰色对象时使用一个分布式算法来检测.在此时,gc转向mark termiation。

  3. gc执行mark termination
    a. stop the world
    b. 将gcphase 改为_GCmarktermination. 然后disable workers和assists(辅助)
    c. 清洗mcaches

  4. gc 改变sweep phase
    a. 将gcphase 改为_GCoff. 设置为sweep状态,暂停写屏障
    b. start the world. 从这个点开始所有新申请的对象都是白色的
    c. gc 在后台并发执行回收操作

  5. 当足够的申请时优惠执行以上操作

初始化

mgc.go
初始化gcPercent和triggerRatio

func gcinit() {

	// No sweep on the first cycle.
	mheap_.sweepdone = 1

	// Set a reasonable initial GC trigger.
	memstats.triggerRatio = 7 / 8.0
	// Set gcpercent from the environment. This will also compute
	// and set the GC trigger and goal.
	_ = setGCPercent(readgogc())
}
func readgogc() int32 {
	p := gogetenv("GOGC")
	if p == "off" {
		return -1
	}
	if n, ok := atoi32(p); ok {
		return n
	}
	return 100
}

在为对象分配堆内存时,mallocgc函数会检查垃圾回收出发条件,并按照相关状态启动或者参与辅助回收.
``
malloc.go

	// assistG is the G to charge for this allocation, or nil if
	// GC is not currently active.
	var assistG *g
	if gcBlackenEnabled != 0 { //辅助回收
		// Charge the current user G for this allocation.
		assistG = getg()
		if assistG.m.curg != nil {
			assistG = assistG.m.curg
		}
		// Charge the allocation against the G. We'll account
		// for internal fragmentation at the end of mallocgc.
		assistG.gcAssistBytes -= int64(size)

		if assistG.gcAssistBytes < 0 {
			// This G is in debt. Assist the GC to correct
			// this before allocating. This must happen
			// before disabling preemption.
			gcAssistAlloc(assistG)
		}
	}
//直接分配黑色对象
	// Allocate black during GC.
	// All slots hold nil so no scanning is needed.
	// This may be racing with GC so do it atomically if there can be
	// a race marking the bit.
	if gcphase != _GCoff {
		gcmarknewobject(uintptr(x), size, scanSize)
	}

当mcache中没有可用对象时会返回shouldhelpgc=true,根据这个字段mallocgc中如果达到gcTrigger会开启辅助回收

	if
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值