内存与 GC 知识体系概览
问题
Go 的内存管理模型是怎样的?垃圾回收算法是什么?如何进行内存调优?
答案
Go 的内存管理是自动的——开发者不需要手动 malloc/free,由 Go 运行时的垃圾回收器(GC)自动管理。理解 Go 的内存模型对于写出高性能程序至关重要。
知识体系总览
核心知识点
1. 栈 vs 堆
| 特性 | 栈(Stack) | 堆(Heap) |
|---|---|---|
| 分配速度 | 极快(移动指针) | 较慢(需要 GC 管理) |
| 回收 | 函数返回自动回收 | GC 回收 |
| 大小 | goroutine 栈初始 2KB~8KB,动态增长 | 几乎无限 |
| 分配条件 | 编译器确认变量不逃逸 | 变量逃逸到堆 |
目标:尽量让变量分配在栈上(不触发 GC),避免不必要的堆分配。
2. 逃逸分析
编译器在编译时决定变量分配在栈还是堆。查看逃逸分析结果:
go build -gcflags="-m" main.go
常见逃逸场景:
- 函数返回局部变量指针
- 发送到 Channel 的指针
- interface 参数
- 闭包引用的变量
- 超大对象
3. 三色标记 GC
Go 使用并发三色标记清扫算法:
- 初始:所有对象标记为白色
- 标记:从根对象开始,标记可达对象(白→灰→黑)
- 清扫:剩余白色对象即为垃圾,回收
通过混合写屏障(Go 1.8+)实现并发标记,STW 时间极短(通常 < 1ms)。
4. GC 调优
# GOGC 控制 GC 频率(默认 100,即堆增长 100% 时触发)
GOGC=200 ./myapp # 降低 GC 频率(减少 CPU 开销,增加内存使用)
GOGC=50 ./myapp # 提高 GC 频率(减少内存使用,增加 CPU 开销)
GOGC=off ./myapp # 关闭 GC(仅用于测试)
# Go 1.19+: GOMEMLIMIT 设置内存上限
GOMEMLIMIT=1GiB ./myapp # 限制堆内存上限为 1GB
5. pprof 内存分析
import _ "net/http/pprof"
go func() {
http.ListenAndServe("localhost:6060", nil)
}()
# 堆内存分析
go tool pprof http://localhost:6060/debug/pprof/heap
# 分配次数分析
go tool pprof -alloc_objects http://localhost:6060/debug/pprof/heap
关键分类文档导航
| 文档 | 核心内容 |
|---|---|
| 内存模型与分配器 | 栈/堆、TCMalloc 分配器、内存对齐 |
| 逃逸分析 | 逃逸场景、优化策略、-gcflags 分析 |
| GC 三色标记 | 标记清扫算法、写屏障、STW |
| GC 调优 | GOGC、GOMEMLIMIT、GC 日志 |
| pprof 内存分析 | 堆分析、goroutine 分析、火焰图 |
| 内存泄漏排查 | 常见泄漏场景、排查工具 |
| sync.Pool 与对象复用 | 对象池原理、使用场景 |
| 减少内存分配 | 优化技巧、零分配模式 |
面试重点
高频面试问题
- Go 的 GC 算法是什么?STW 有多长?
- 什么是逃逸分析?哪些情况会逃逸?
- 如何用 pprof 排查内存问题?
- GOGC 和 GOMEMLIMIT 怎么配?
- Go 内存泄漏的常见场景?