Go垃圾回收
GC原理
现代高级编程语言管理内存的方式分为两种:自动和手动,像 C、C++ 等编程语言使用手动管理内存的方式,
工程师编写代码过程中需要主动申请或者释放内存;
而 PHP、Java 和 Go 等语言使用自动的内存管理系统,有内存分配器和垃圾收集器来代为分配和回收内存,
其中垃圾收集器就是我们常说的 GC。
主流的垃圾回收算法包含”引用计数“和”追踪式垃圾回收“,go的三色标记法就是追踪式垃圾回收的一种。
在垃圾回收中,应用程序称为Mutator,内存分配器称为Allocator,垃圾回收器称为Collector,内存堆称为Heap。
Mark & Sweep(标记和清除)
垃圾回收包含Mark(标记)和Sweep(清除)这两个阶段,有两个术语:
- STW:即stop the word,在GC的一些阶段需要停止所有的应用程序以确定当前的引用关系,是GC算法优化的重点。
- Root对象:指不需要通过其他对象就可以直接访问到的对象,如全局对象、栈对象中的数据等。
通过root对象,可以追踪到其他存活的对象。
传统的Mark & Sweep大致流程:
- stop the world: 停止所有应用程序的运行
- Mark: 通过Root对象和Root直接间接访问到的对象来寻找所有可达对象,并进行标记
- Sweep: 对堆对象进行迭代,未标记的对象加入freelist用于再分配
- start the world:程序重新运行
这个算法最大的缺陷就是GC期间整个程序完全停止,需要在mark和sweep的整个阶段STW。
之后引入并发的GC概念,实现了:
- mark或sweep步骤可以多个协程同时进行
- 应用程序mutator可以和垃圾收集collector同时运行
go1.3之后,分离了标记和清除操作,使得mark阶段仍然需要STW,但标记后的sweep和程序可以同时运行。
go1.5之后,标记采用三色标记,标记和清扫都是并发执行,但标记阶段的前后需要 STW 一定时间来做 GC 的准备工作和栈的re-scan。
三色标记法
三色标记将对象标记黑、灰、白三种颜色,大致流程是:
一开始所有对象是白色,从root对象开始标记为灰色,之后从灰色对象列表中开始,将灰色标记为黑色,将其引用的对象再标记为灰色,
直到最后所有引用的对象都是黑色,未引用的数据为白色。
标记结束后,黑色为内存中正在使用的对象,白色是要回收的对象。
Write Barrier(写屏障)
1.5版本在标记过程中使用三色标记法,标记和清扫都并发执行的,但标记阶段的前后需要 STW 一定时间来做GC 的准备工作和栈的 re-scan。
在并发的垃圾回收中,要保证最后的正确性,必须要满足两种三色不变性的一种:
强三色不变性:黑色对象不会指向白色对象,只会指向灰色对象或者黑色对象。
弱三色不变性:黑色对象指向的白色对象必须包含一条从灰色对象经由多个白色对象的可达路径。
-
Write Barrier - Dijkstra 写屏障
插入屏障拦截将白色指针插入黑色对象的操作,标记其对应对象为灰色状态,这样就不存在黑色对象引用白色对象的情况了,满足强三色不变式,在插入指针 f 时将 C 对象标记为灰色。 -
Write Barrier - Yuasa 删屏障
也是拦截写操作,是通过”保护灰色对象到白色对象的路径不会断“来实现的。
- 混合屏障
STW
在 “Stop the World” 阶段, 当前运行的所有程序将被暂停, 扫描内存的 root 节点和添加写屏障 (write barrier) 。
Pacing 超过100%内存或者两分钟没有GC会强制触发GC。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY