golang垃圾回收机制

摘要:
Golang的GC(1.8)通过混合写屏障将STW减少到subs。在go语言中,程序代码执行和垃圾收集是同时执行的。默认情况下,垃圾收集以完全并发模式运行。GCgoroutine循环执行,直到满足触发条件时被唤醒//将灰色对象从队列中取出,其引用对象变灰,并且其引用对象也变灰。FuncgcBgMarkStartWorker(){//Backgroundmarkingsformedtyper PG。确保//每个PhasabackgroundGCG.for_,p:=rangeallp{ifp.gcBgMarkWorker==0{gogcBgmarkWorkerotesleepgnoteclear}}}}垃圾清理所有未标记的白色对象不再被引用,它们的内存可以被回收//无限循环,唤醒后执行并发清理任务,完成后回收内存,等待下一次执行funcbgsweep{sweep.g=getg()locksleep.marked=true c˂-1Oparkunlockfor{forsweepe()!

golang的GC,1.8通过混合写⼊屏障, 使得STW降到了sub ms。go语言中程序代码执行和垃圾回收是并发执行的。

当前Go GC特征 :
三色标记,并发标记和清扫,非分代,非紧缩,混合写屏障。
三色标记:
1. 将所有对象放在白色集合中
2. 从rootset遍历可达对象,将可达对象放在灰色集合中
3. 将灰色集合中对象进行遍历,将可达对象放在灰色集合中,将其本身放在黑色集合中
4. 重复第三步,直到灰色集合遍历为空
5. 将白色集合中的对象视为垃圾进行清扫
6. 重置黑色集合对象,将其变为白色,进行下次GC

gc写屏障解决垃圾回收并发的问题:

写屏障是在写入指针前执行的一小段代码,用以防止并发标记时指针丢失,这段代码Go是在编译时加上的。
如果以下代码没有写屏障,则当代码执行和垃圾回收并发执行时,GC垃圾回收扫描到obj1为nil,将其标记为回收对象,此时代码重新给obj1和obj2赋值,obj2为nil,垃圾回收将obj2标记为回收对象,此时obj1和obj2都会被回收,但obj1此时是不需要回收的

func (obj *Object) Demo() {
//初始化
obj1 = nil
obj2 = obj
//gc 垃圾回收开始⼯作
//扫描对象 obj1 完成后
//代码修改为:对象重新赋值
obj1 = obj
obj2 = nil
//扫描对象 obj2
}


GC触发
1. 分配内存时, 当前已分配内存与上一次GC结束时存活对象的内存达到某个比例时就触发GC。
2. sysmon检测2min内是否运行过GC, 没运行过 则执行GC。
3. runtime.GC()强制触发GC。

垃圾回收默认是全并发模式运行,GC goroutine 一直循环执行,直到符合触发条件时被唤醒。

并发标记分为两个步骤:
扫描:遍历相关内存区域,依次按照指针标记找出灰色可达对象,加入队列。
标记:将灰色对象从队列取出,将其引用对象标记为灰色,自身标记为黑色。

// 将灰色对象从队列取出,其引用对象标灰,自身标黑
func gcBgMarkStartWorkers() {
	// Background marking is performed by per-P G's. Ensure that
	// each P has a background GC G.
	for _, p := range allp {
		if p.gcBgMarkWorker == 0 {
			go gcBgMarkWorker(p)
			notetsleepg(&work.bgMarkReady, -1)
			noteclear(&work.bgMarkReady)
		}
	}
}

垃圾清理
所有未标记的白色对象不再被引用,可以将其内存回收。

// 无限循环,被唤醒后执行并发清理任务,完成后回收内存等待下次执行
func bgsweep(c chan int) {
	sweep.g = getg()

	lock(&sweep.lock)
	sweep.parked = true
	c <- 1
	goparkunlock(&sweep.lock, waitReasonGCSweepWait, traceEvGoBlock, 1)
        
	for {
		for sweepone() != ^uintptr(0) {
			sweep.nbgsweep++
			Gosched()
		}
		for freeSomeWbufs(true) {
			Gosched()
		}
		lock(&sweep.lock)
		if !isSweepDone() {
			// This can happen if a GC runs between
			// gosweepone returning ^0 above
			// and the lock being acquired.
			unlock(&sweep.lock)
			continue
		}
		sweep.parked = true
		goparkunlock(&sweep.lock, waitReasonGCSweepWait, traceEvGoBlock, 1)
	}
}

免责声明:文章转载自《golang垃圾回收机制》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇AWTK 中 LCD 接口的四种实现方式如何高效判断java数组是否包含某个值下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

golang的传值调用和传引用调用

传值还是传引用 调用函数时, 传入的参数的 传值 还是 传引用, 几乎是每种编程语言都会关注的问题. 最近在使用 golang 的时候, 由于 传值 和 传引用 的方式没有弄清楚, 导致了 BUG. 经过深入的尝试, 终于弄明白了 golang 的 传值 的 传引用, 尝试过程记录如下, 供大家参考! golang 本质上都是传值方式调用 严格来说, go...

Golang: 解析JSON数据之一

JSON 作为目前最流行的数据传输格式, 相信每个程序员都跟它打过交道吧。使用 Go 语言时,也不可避免的要操作 JSON 数据,令人惊喜的是,Go 内置了序列化和反序列化 JSON 的功能,今天就来总结一下。 序列化是将结构对象转为 JSON 字符串,反序列化是将 JSON 字符串转为结构对象,它们分别对应 encoding/json 包下面的两个方法:...

golang网关之手动实现反向代理

简单说说反向代理    信号监听方式启动两个web服务,分别是9091 9092 分别返回 web1 web2 webmain.go type web1handler struct {} func(web1handler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {...

golang闭包和range,关于闭包内使用外部变量

遇到经典问题 func mian() { resslice := []int{1, 2, 3, 4} for _, v := range resslice { fmt.Println(v) defer fun1(v) } } func fun1(value int) { fmt.Println(value) }   输出结果为...

golang-指针,函数,map

指针普通类型变量存的就是值,也叫值类型。指针类型存的是地址,即指针的值是一个变量的地址。一个指针只是值所保存的位置,不是所有的值都有地址,但是所有的变量都有。使用指针可以在无需知道变量名字的情况下,间接读取或更新变量的值。 获取变量的地址,用&,例如:var a int 获取a的地址:&a,&a(a的地址)这个表达式获取一个指向整型...

golang使用etcd实现分布式锁

1 package main 2 3 import ( 4 "context" 5 "fmt" 6 "time" 7 8 "go.etcd.io/etcd/clientv3" 9 ) 10 11 func main() { 12 var ( 13 client *clientv...