温馨提示×

linux golang为何内存泄漏

小樊
44
2026-10-12 23:04:44
栏目: 编程语言

在 Linux 上用 Go(Golang)写程序时,很多人以为“有 GC 就不会内存泄漏”,但实际上Go 也会内存泄漏,而且常见原因和 C/C++ 不太一样。下面从原理 + 常见原因 + 排查方法系统讲一下。


一、先澄清:Go 里的“内存泄漏”是什么

Go 有 GC,所以传统意义的“忘了 free”几乎不存在。
但 Go 的“内存泄漏”通常指:

本该被回收的对象,因为仍然被引用,导致一直占用内存,且不断增长

GC 只能回收不可达对象,只要还有引用,就不会回收。


二、Linux 上 Go 常见内存泄漏原因

1️⃣ 全局变量 / 单例缓存无限增长(最常见)

var cache = map[string][]byte{}

func addCache(k string, v []byte) {
    cache[k] = v
}
  • key 只增不减
  • slice / map 一直引用
  • GC 永远回收不了

✅ 解决:

  • 用 sync.Map
  • 加 TTL(过期)
  • 用 lru 缓存库

2️⃣ Goroutine 泄漏(非常常见)

func worker() {
    ch := make(chan int)
    go func() {
        for v := range ch {
            _ = v
        }
    }()
    // ch 没 close,goroutine 永远阻塞
}
  • goroutine 不退出
  • 栈 + 捕获变量一直存在
  • pprof 里 goroutine 数量爆炸

✅ 解决:

  • channel 要明确 close
  • 用 context.Context 控制生命周期
  • 避免永久阻塞

3️⃣ Timer / Ticker 未 Stop

ticker := time.NewTicker(time.Second)
go func() {
    for range ticker.C {
        // do something
    }
}()
// 忘记 ticker.Stop()
  • Ticker 内部有 goroutine
  • 不 Stop = 泄漏

✅ 解决:

defer ticker.Stop()

4️⃣ Slice 截取导致底层数组不释放

big := make([]byte, 10<<20)
small := big[:10]
// small 一直被引用
// 底层 10MB 数组无法释放

✅ 解决:

small := make([]byte, 10)
copy(small, big[:10])

5️⃣ 闭包捕获大对象

func handler() func() {
    big := make([]byte, 1<<20)
    return func() {
        _ = len(big)
    }
}
  • 返回的 func 活着
  • big 就活着

6️⃣ CGO 内存泄漏(Linux 特别要注意)

C.malloc(1024)
// 忘记 C.free
  • Go GC 管不到 C 的内存
  • top 看 RSS 一直涨

✅ 解决:

  • 明确 C.free
  • 或不用 CGO

7️⃣ 文件 / 连接未关闭

resp, _ := http.Get(url)
// 忘记 resp.Body.Close()
  • fd 泄漏
  • 间接导致内存问题

8️⃣ Go Runtime 本身“看起来像泄漏”

正常情况:

  • RSS > 实际使用内存
  • Go 向 OS 申请内存后不轻易还

可用:

GODEBUG=madvdontneed=1

或:

debug.FreeOSMemory()

⚠️ 一般不建议强行调用


三、Linux 下如何排查 Go 内存泄漏

1️⃣ 内置 pprof(最强)

import _ "net/http/pprof"

go func() {
    http.ListenAndServe(":6060", nil)
}()

查看:

go tool pprof http://localhost:6060/debug/pprof/heap

重点看:

  • inuse_space
  • goroutine

2️⃣ 看 Goroutine 数

curl http://localhost:6060/debug/pprof/goroutine?debug=1

持续增长 = 泄漏


3️⃣ Linux 命令辅助

top -p PID
cat /proc/PID/status
pmap -x PID

四、一句话总结

Linux 上 Go 内存泄漏,99% 不是 GC 的锅,而是“你还引用着”。

最常见三类:

  1. goroutine 泄漏
  2. 全局 map / slice 无限增长
  3. CGO / 系统资源未释放

如果你愿意,可以:

  • 贴一段代码
  • 或贴 pprof 输出

我可以直接帮你定位是哪一类泄漏。

0 踩