

新闻资讯
技术学院Go指针易引发内存泄漏、goroutine泄漏、data race、逃逸分析失控及nil解引用panic,应优先使用值语义,仅在必要时用指针。
Go 的垃圾回收器无法回收仍被指针引用的对象,哪怕逻辑上已不再需要。常见于缓存、全局 map 或 channel 中存储了指向大结构体的指针,而忘记清理或未设过期机制。
sync.Map 或全局 map[string]*BigStruct 插入后长期不删除,*BigStruct 及其引用的子对象持续驻留内存go func() {
use(ptrToLocalVar) // 即使函数返回,ptrToLocalVar 所指内存仍可能被 goroutine 持有
}()若该 goroutine 运行时间远超原函数生命周期,就构成隐式内存泄漏多个 goroutine 同时通过不同指针修改同一底层数据,且无同步保护,是 Go 中最典型的 data race 场景。go build -race 会报类似 Read at 0x00c000123456 by goroutine 7 的错误。
*sync.Mutex 实例却在不同 goroutine 中各自 new 出新指针:mu := &sync.Mutex{} → 每次都新建,锁失效data *[]byte),两个 goroutine 分别解引用并追加元素:*s.data = append(*s.data, x) → 底层数组扩容后旧地址失效,另一 goroutine 写入野指针unsafe.Pointer 强转并并发修改,绕过 Go 类型系统检查,race detector 也难以捕获编译器发现变量地址被外部获取(如返回局部变量地址、传给 goroutine、存入切片/映射),就会强制将其分配到堆上。滥用指针会让本可栈分配的小对象全部逃逸。
func bad() *int {
x := 42
return &x // x 必然逃逸到堆,即使只用一次
}相比直接返回 int,多一次堆分配+GC 压力[]*Item 对比 []Item —— 前者每个 *I
tem 独立堆分配,后者整体连续分配,缓存友好性差一个数量级json.Unmarshal 接收 *struct{} 是必须的,但若对小结构体(如 type ID struct{ N int })也坚持传 *ID,反而增加间接寻址开销Go 不做空指针防护,nil 指针解引用直接 panic,堆栈常只显示 panic: runtime error: invalid memory address or nil pointer dereference,不指明具体字段或调用链。
a.b.c.d.E.Name),任一环节为 nil 都会导致 panic,但运行时无法静态检查nil:如果方法内未做 if p == nil 判断,就直接访问字段或调用其他方法,panic 发生点远离原始赋值处*T,文档未明确是否可能为 nil,使用者忽略判空,上线后偶发 crashstruct{} 比 *struct{} 更轻、更安全、更易推理。