第七章 内存与GC 更新ing
内存与 GC:理解 Go 内存分配(TCMalloc 启发的堆 / 栈管理、逃逸分析)、垃圾回收(G1 / 三色标记算法、GC 触发时机与优化),能通过pprof排查内存泄漏、GC 耗时过高问题;
第一部分 自动内存管理
一、自动内存管理简介
1.基本概念
由程序语言的运行时系统管理动态内存,避免手动内存管理,保证内存使用的正确性与安全性。
(避免 double-free problem<二次释放内存>、use-after-free problem<二次使用已释放内存>)
自动内存管理三个基本任务:为新对象分配空间、找到存活对象、回收死亡对象的内存空间。
相关概念:
Mutator:业务线程,分配新对象,修改对象指向关系。
Collector:GC线程,找到存活对象,回收死亡对象的内存空间。
Serial GC:只有一个 collector。
Parallel GC:支持多个 collector 同时回收的 GC 算法。
Concurrent GC:mutator(s) 和 collector(s) 可以同时执行(Collector 必须感知对象指向关系改变)。

2.相关概念详解
追踪垃圾回收
回收条件:指针指向关系不可达的对象。
流程:标记根对象 ->(根据指针指向关系的传递闭包)找到可达对象 -> 清理所有不可达对象。
几种清理方法:
- 将存活对象复制到另外的内存空间(Copying GC)
- 将死亡对象的内存标记为“可分配”(Mark-sweep GC)
- 移动并整理存活对象(Mark-compact GC)
分代GC(Generational GC)
目的:针对年轻和老年(年龄为经历GC数)的对象,制定不同的GC策略,降低整体内存管理开销。
年轻代:常规对象分配,存活对象少,可以使用 Copying GC,GC吞吐量高。
老年代:对象趋向于一直活着,反复复制开销较大,可以采用 Mark-sweep GC。
引用计数(Reference counting)
存活条件:当且仅当引用数大于0。
优点:
- 内存管理的操作被平摊到程序执行过程中
- 内存管理不需要了解 runtime 的实现细节:C++智能指针(smart pointer)
缺点:
- 维护引用计数的开销较大:通过原子操作保证对引用计数操作的原子性和可见性
- 无法回收环形数据结构——weak reference
- 内存开销:每个对象都引入额外内存空间存储引用数目
- 回收内存时依然可能引发暂停
二、Go语言自动内存管理
1.自动内存管理目标
为对象在 heap 上分配内存。
2.方式
提前将内存分块:
- 调用系统调用 mmap(向 OS 申请一大块内存,例如 4 MB)
- 先将内存划分成大块,例如 8 KB,称作 mspan
- 再将大块继续划分成特定大小的小块,用于对象分配
- noscan mspan:分配不包含指针的对象,GC不需要扫描
- scan mspan:分配包含指针的对象,GC需要扫描
3.Go对象分配的性能问题
① 分配路径过长 ② 小对象居多