想象你开了家小超市,货架上摆满了商品(就像程序里的"内存")。顾客买东西时,你会把商品从仓库搬到货架(程序创建变量、对象时,会占用内存)。
但问题来了:有些商品放了很久没人买,一直占着货架(程序里不再使用的变量,还占着内存),新来的商品就没地方放了。这些"没人要的商品",就是程序里的"垃圾"。
垃圾回收的作用,就是自动把这些"没人要的商品"清走,腾出空间给新商品。
手动清理垃圾很麻烦(比如 C 语言要手动 free),Go 则像雇了个保洁员,定期来店里盘点:
早期的垃圾回收有个大问题:保洁员干活时,超市得停业(程序暂停,即"Stop The World"),顾客全等着,体验很差。
但 Go 的保洁员很聪明,用了几个技巧:
现在的保洁员不用让超市停业了。她盘点的时候,顾客照样可以买东西、上架新商品(标记阶段与用户程序同时运行)。
这就像餐厅服务员收拾桌子:客人还在吃饭时,服务员可以先把空盘子收走,不用等所有人吃完。
超市发现一个规律:刚上架的商品(新创建的对象),往往很快就被买走或下架(生命周期短);而放了很久的老商品(长期存活的对象),大概率会一直放着。
所以保洁员会重点检查刚上架的区域(优先回收新对象),老商品区域很久才查一次。这样效率更高,就像家里打扫时,厨房(常用区域)每天擦,衣柜(不常用)半年整理一次。
为了在"边营业边盘点"时不出错(比如刚标记完,顾客又把商品换了位置),保洁员用了三个颜色的标签:
一开始所有商品都是白色。保洁员先把顾客手里正拿着的商品(根对象)标为灰色,然后逐个检查灰色商品关联的其他商品(比如礼盒里的赠品),都标完后再把灰色改成黑色。最后剩下的白色商品,就是没人要的垃圾。
这个过程中如果有新商品上架(程序创建新对象),会直接标为灰色,保证不会被误当成垃圾清走。
万一保洁员刚标完黑色,有顾客偷偷把商品换了(程序修改了对象引用)怎么办?
Go 用了"写屏障"技术,就像在货架旁装了监控:只要有人动了已经标记好的商品,立刻通知保洁员,确保盘点结果准确。
Go 的垃圾回收机制核心是自动识别并回收不再使用的内存,其原理基于并发标记 - 清除算法:首先通过 “三色标记法” 追踪对象引用 —— 初始所有对象为白色(未检查),从根对象开始遍历,将可达对象标记为灰色(待处理),处理完所有关联引用后转为黑色(存活),剩余白色即为垃圾;标记阶段与用户程序并发执行,同时通过 “写屏障” 技术监控对象引用变化,防止标记过程中因引用修改导致的遗漏或误判。标记完成后进入清除阶段,回收所有白色对象内存并整理,供新对象分配使用。此外,结合分代回收思想,对新创建的短生命周期对象优先回收,减少对长期存活对象的扫描频率,显著降低 STW(Stop The World)时间。这一机制无需手动管理内存,兼具低延迟特性,是 Go 支持高并发场景的重要基础。