GC Roots (根节点) 是可达性分析的起点。它们是程序运行中绝对不可回收的“种子”对象,GC 通过它们顺藤摸瓜,找出所有还在使用的内存。
核心逻辑:顺藤摸瓜
在 Go 的内存管理中,判断对象死活不是靠“计数”,而是靠“能不能被找到”。
| 概念 | 形象类比 | 技术定义 |
|---|---|---|
| GC Roots | 树的根部 | 垃圾回收的起始搜索点 |
| 可达对象 | 树干与枝叶 | 从根节点出发,通过指针能找到的对象 |
| 不可达对象 | 掉落在地的枯叶 | 无法从根节点触达的内存,即“垃圾” |
哪些对象能当“根”?
并不是所有变量都有资格成为 GC Roots,它们必须是程序执行的“现场”或“全局基石”。
| Root 类型 | 存储位置 | 为什么它是 Root? |
|---|---|---|
| 局部变量 | Goroutine 栈 (Stack) | 正在运行的函数现场,引用的对象随时会被读写。 |
| 全局变量 | 数据段 (Data Segment) | 程序生命周期内恒常存在,随时可能被访问。 |
| 寄存器 | CPU Registers | 正在被 CPU 调度计算的临时指针。 |
根节点在三色标记中的角色
在 三色标记法 启动时,GC 第一步就是扫描所有的 GC Roots:
- 初始标记:将所有 GC Roots 直接引用的对象标记为 灰色。
- 并发扫描:从这些灰色对象开始,递归向下寻找。
挑战与对策
| 挑战 (Challenge) | 技术对策 (Strategy) |
|---|---|
| 扫描根节点时程序还在运行怎么办? | 使用 STW (Stop The World) 短暂挂起,或配合 写屏障。 |
| 栈上对象太多,扫描慢? | 每个 Goroutine 独立扫描,利用并发能力。 |