Go 后端内存排查:pprof 定位泄漏与 OOM 兜底

举报
yd_278073926 发表于 2026/11/05 06:12:12 2026/11/05
【摘要】 Go 后端内存排查:pprof 定位泄漏与 OOM 兜底点餐小程序的 Go 后端跑在 2 核 2G 的 Flexus L 上,某天晚上突然重启,查日志只看到一行 “out of memory: Killed process”。内存从几百兆一路涨到 2G,没人发现,直到 OOM Killer 动手。事后我用 pprof 把泄漏找了出来,顺手给服务加了两道兜底。第一步是复现与定位。Go 自带 ...

Go 后端内存排查:pprof 定位泄漏与 OOM 兜底

点餐小程序的 Go 后端跑在 2 核 2G 的 Flexus L 上,某天晚上突然重启,查日志只看到一行 “out of memory: Killed process”。内存从几百兆一路涨到 2G,没人发现,直到 OOM Killer 动手。事后我用 pprof 把泄漏找了出来,顺手给服务加了两道兜底。

第一步是复现与定位。Go 自带 pprof,在 main 里 import _ “net/http/pprof” 并起一个调试端口,就能在 /debug/pprof/heap 看到实时堆内存。更直接的办法是抓两次 heap profile 对比:curl -o heap1.out http://localhost:6060/debug/pprof/heap,隔十分钟再抓 heap2,然后 go tool pprof -base heap1.out heap2.out,用 top 命令看增长最多的调用栈。我那次抓出来,增长最快的是一个被遗忘的定时器 goroutine——每分钟启动一个 ticker,却没有在请求结束时 Stop,导致 goroutine 和它持有的连接对象越积越多。

第二步是修泄漏的常见模式。Go 内存泄漏大多不是真的"丢了指针",而是对象还被某个地方引用着,GC 回收不掉。最常见的三类:goroutine 泄漏(channel 没人接收、select 永远等不到、ticker 没 Stop)、缓存无上限(map 只进不出,必须加容量上限和过期淘汰)、HTTP 响应体没 Close(resp.Body 不关,连接和内存都回不去池里)。修的时候按"谁创建谁释放"的原则,defer 能解决的就地解决;缓存则用带 TTL 的结构,超过阈值直接淘汰。

第三步是给小内存服务器加兜底。定位工具再好,也防不住下一次意外增长。我的做法是三层:第一层是 Go 运行时的 GOMEMLIMIT,设成总内存的七成左右,GC 会提前发力回收;第二层是 systemd 的 MemoryMax,写进 service 文件,超了就重启服务而不是让 OOM Killer 随机杀进程;第三层是监控告警,写个每分钟跑的脚本看 RSS,超过阈值就发消息提醒,宁可早知道不要半夜被叫醒。

第四步是日常巡检的习惯。2G 内存的服务器经不起"上线就忘",我每周看一次三组数:go_memstats_alloc_bytes 看 Go 堆,RSS 看进程真实占用,系统剩余内存看整机余量。配合 pprof 的 goroutine 数(goroutine 数量异常上涨往往是泄漏的第一信号),大部分问题在变大之前就能发现。

内存泄漏不可怕,可怕的是没有观测手段。pprof 定位、修三类常见泄漏、再加 GOMEMLIMIT、MemoryMax 和告警三道兜底,2G 小服务器也能跑得稳。排查工具是手段,让问题在造成影响之前被发现,才是目的。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。