011-Golang1.17源码分析之GC

Golang1.17源码分析之GC-011

Golang1.17 学习笔记011

GC 目前采用的是三色标记清除法

三色:黑、灰、白

黑色:被引用,不清理,追踪完成,gcmarkBits 对应的位为 1

灰色:可能被引用,需要再次扫描,未追踪完成

白色:没有被引用,或尚未追踪,gcmarkBits 对应的位为 0

11.1 内存标记

span 中维护了一个个内存块,并由一个位图 allocBits 表示每个内存块的分配情况。
在 span 数据结构中还有另一个位图 gcmarkBits 用于标记内存块被引用情况

标记阶段对每块内存进行标记,有对象引用的的内存标记为 1,没有引用到的保持默认为 0.

allocBits 和 gcmarkBits 数据结构是完全一样的,标记结束就是内存回收,回收时将 allocBits 指向 gcmarkBits,
则代表标记过的才是存活的,gcmarkBits 则会在下次标记时重新分配内存

11.2 STW

STW(stop the world),就是停掉所有协程,专注于 GC

11.3 垃圾回收优化

  1. 写屏障

写屏障类似一种开关,在GC的特定时机开启,开启后指针传递时会把指针标记,即本轮不回收,下次GC时再确定

  1. 辅助 GC

为了防止内存分配过快,在 GC 执行过程中,如果 goroutine 需要分配内存,那么这个 goroutine 会
参与一部分 GC 的工作,即帮助 GC 做一部分工作,这个机制叫作 Mutator Assist

11.4 垃圾回收触发时机

  1. 内存分配达到阈值时进行触发

阀值 = 上次GC内存分配量 * 内存增长率

内存增长率由环境变量 GOGC 控制,默认为 100,即每当内存扩大一倍时启动 GC

  1. 定期触发

默认情况下,最长 2 分钟触发一次 GC,在 src/runtime/proc.go:forcegcperiod 变量中被声明:


var forcegcperiod int64 = 2 * 60 * 1e9

  1. 手动触发:runtime.GC()

11.5 核心源码

源码包:runtime/mgc.go

func GC() {
	// We consider a cycle to be: sweep termination, mark, mark
	// termination, and sweep. This function shouldn't return
	// until a full cycle has been completed, from beginning to
	// end. Hence, we always want to finish up the current cycle
	// and start a new one. That means:
	//
	// 1. In sweep termination, mark, or mark termination of cycle
	// N, wait until mark termination N completes and transitions
	// to sweep N.
	//
	// 2. In sweep N, help with sweep N.
	//
	// At this point we can begin a full cycle N+1.
	//
	// 3. Trigger cycle N+1 by starting sweep termination N+1.
	//
	// 4. Wait for mark termination N+1 to complete.
	//
	// 5. Help with sweep N+1 until it's done.
	//
	// This all has to be written to deal with the fact that the
	// GC may move ahead on its own. For example, when we block
	// until mark termination N, we may wake up in cycle N+2.

	// Wait until the current sweep termination, mark, and mark
	// termination complete.
	n := atomic.Load(&work.cycles)
	gcWaitOnMark(n)

	// We're now in sweep N or later. Trigger GC cycle N+1, which
	// will first finish sweep N if necessary and then enter sweep
	// termination N+1.
	gcStart(gcTrigger{kind: gcTriggerCycle, n: n + 1})

	// Wait for mark termination N+1 to complete.
	gcWaitOnMark(n + 1)

	// Finish sweep N+1 before returning. We do this both to
	// complete the cycle and because runtime.GC() is often used
	// as part of tests and benchmarks to get the system into a
	// relatively stable and isolated state.
	for atomic.Load(&work.cycles) == n+1 && sweepone() != ^uintptr(0) {
		sweep.nbgsweep++
		Gosched()
	}

	// Callers may assume that the heap profile reflects the
	// just-completed cycle when this returns (historically this
	// happened because this was a STW GC), but right now the
	// profile still reflects mark termination N, not N+1.
	//
	// As soon as all of the sweep frees from cycle N+1 are done,
	// we can go ahead and publish the heap profile.
	//
	// First, wait for sweeping to finish. (We know there are no
	// more spans on the sweep queue, but we may be concurrently
	// sweeping spans, so we have to wait.)
	for atomic.Load(&work.cycles) == n+1 && !isSweepDone() {
		Gosched()
	}

	// Now we're really done with sweeping, so we can publish the
	// stable heap profile. Only do this if we haven't already hit
	// another mark termination.
	mp := acquirem()
	cycle := atomic.Load(&work.cycles)
	if cycle == n+1 || (gcphase == _GCmark && cycle == n+2) {
		mProf_PostSweep()
	}
	releasem(mp)
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值