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()强制触发

相关推荐
小满zs3 小时前
Go语言第十七章(反射)
后端·go
小满zs3 小时前
Go语言第十五章(JSON序列化)
后端·go
小满zs3 小时前
Go语言第十六章(自定义类型)
后端·go
w-w0w-w3 小时前
Go语言学习day1
go
FungLeo11 小时前
成为全栈·Go 后端篇·契约一致性与差分测试:两套实现如何互相校验
golang·node.js·go·合约测试·差分测试·成为全栈·api兼容
vipxieliang15 小时前
Go 1.25 Green Tea GC 深度解析:以页为单位的垃圾回收新范式
go
孔令飞16 小时前
AI 时代岗位调研分析:调研了近3000份AI岗位描述,分享下调研结果
云原生·go·ai编程
我不会起名字32216 小时前
Redis 从 0 到 1(十二):先删缓存还是先更新库?4 种方案的 Go 并发实测
redis·go·并发·延迟双删·缓存一致性
FungLeo2 天前
成为全栈·Go 后端篇·用 Go 重写分层架构:领域包、装配根与最小抽象
golang·go·领域驱动设计·gorm·分层架构·成为全栈
我不会起名字3222 天前
Go 服务升级 Go 1.2x 后 P99 变差:GMP 调度相关的 3 个变化
golang·go·gmp·调度·gomaxprocs