golang的垃圾回收

垃圾回收的几种机制

引用计数

过程:

1)当对象被创建时,初始化计数器为1

2)当更新指针时,新指向的对象引用计数加一,旧对象引用计数减一,如果为0则回收掉,放入空闲队列,并且递归的去 更新

优点:

1)实时性高,当对象引用计数为0时,立即回收

2)垃圾回收过程中应用无需挂起

缺点:

1)指针的更新需要手动的去操作,当前对象的引用计数为0时,需要递归更新对象的引用计数

2)无法解决循环引用问题(自循环引用、相互循环引用、多循环引用)

解决循环引用的方法:

1)避免产生循环引用

2)在合适的时机,手动显示的断开

3)弱引用 weak_ptr

标记清除

从root开始一层层扫描,root指当前所有goroutine的栈和全局数据区的变量(主要是这两个)

扫描过程中把所有可达的object标记出来,未被标记的object就需要清除,清除后的object会被放回到mcache中以备后续分配使用

整个过程需要stop the worl,挂起所有用户goroutine

三色标记

对于黑色的object,如果标记期间发生了写操作,写屏障会在真正赋值前将新对象标记为灰色

标记过程中,新分配的object,会先被标记成黑色再返回

对上的object被赋值给一个栈上的指针,写屏障是检测不到的,所以标记的最后阶段,还会回头重新扫描一下所有的栈空间,确保没有遗漏

混合写屏障

不需要最后回头重新扫描所有goroutine的栈空间了,是的整个GC过程中的stw可以忽略不计了

但也带来一些代价,如果C未被赋值给L,却被置灰,只能等下一次GC的时候再进行回收

还有一种情况,当GC过程中新创建的对象(被置黑),也会被下次回收

节点复制

分代收集(新生代和老年代)

将堆划分为两个多个称为代的空间,新创建的对象放在新生代中,随着垃圾回收的重复执行,生命周期长的对象会被提升到老年代中

golang的GC

1)1.3版本以前,go runtime在一定条件下(内存超过阈值或定期2min)暂停所有任务的执行,进行mark&sweep操作,操作完成后启动所有任务的执行,整个过程需要stw,挂起所有goroutine

2)1.3版本开始,go runtime分离了mark和sweep操作,也是先暂停所有任务执行并启动mark,mark完之后就重新启动被暂停的任务,让sweep任务和普通协程任务一样并行的一起执行。如果运行在多核处理器上,go会试图让gc任务放到单独的核心上运行,尽量不影响业务代码的执行,标记过程stw,清除过程并行

3)1.4版本,runtime很多代码取代了原生的c语言,采用go语言实现

4)1.5版本,三色标记清除垃圾收集器(非分代的、非移动的、并发的),三色标记法的mark操作是可以渐进执行的,而不需要每次都扫描整个内存空间,可以减少stop the world的时间,三色标记+写屏障

5)1.8版本,Hibrid write Barrier(混合写屏障),不需要最后回头重新扫描所有goroutine的栈空间

GC何时被触发

1)堆上内存达到一定数值

2)每隔2min,强制触发

3)用户手动触发,使用runtime.GC()强制触发

相关推荐
用户342323237631712 小时前
开源!Go+Wails+Vue3 手搓一个 PLC 实时监控桌面工具
go
止语Lab13 小时前
为什么你的 Go TCP server P99 延迟这么高
go
Andy Dennis19 小时前
nsq学习记录
消息队列·go·nsq
韦胖漫谈IT21 小时前
选语言不是站队,是选适合问题的工具
java·python·ai·rust·go·技术落地
喵个咪1 天前
GoWind Toolkit Go后端代码生成 完整全流程实战
后端·go·orm
夜悊2 天前
Go网络编程的学习代码示例:客户端/服务端(C/S)模型
go
审判长烧鸡2 天前
【AI问答】GO代码循环返值
go
捧 花2 天前
Eino框架记忆功能实现指南
go·agent·eino
Java陈序员2 天前
主流数据库通吃!一款开源实用的数据库备份管理工具!
react.js·postgresql·go
云浪2 天前
搞懂 Go WaitGroup:一篇文章彻底理解并发等待机制
后端·go