乐趣区

关于golang:记一次-Go-服务内存泄漏问题调查

生产环境服务内存透露问题考察

记录下这个问题是因为这不同于传统典型的 Go 服务内存透露。

8 月 15 日前后,钉钉监控告警群不定时呈现服务机器内存占用超 80%
告警,一开始认为是 Prometheus exporter 沉积造成的,筹备下掉 Prometheus
exporter 的集成代码,起初觉 得这个沉积速度太快了点,不到一天就吃掉
6GB,非常夸大,所以有空的时候用 gops 快照了 一下,内存状况如下图

(pprof) /app/bin # gops memstats 1
alloc: 54.66MB (57317968 bytes)
total-alloc: 186.21GB (199938346560 bytes)
sys: 6.72GB (7215977904 bytes)
lookups: 0
mallocs: 2906600570
frees: 2906521966
heap-alloc: 54.66MB (57317968 bytes)
heap-sys: 6.44GB (6909984768 bytes)
heap-idle: 6.38GB (6846406656 bytes)
heap-in-use: 60.63MB (63578112 bytes)
heap-released: 6.33GB (6794371072 bytes)
heap-objects: 78604
stack-in-use: 2.12MB (2228224 bytes)
stack-sys: 2.12MB (2228224 bytes)
stack-mspan-inuse: 266.02KB (272408 bytes)
stack-mspan-sys: 31.88MB (33423360 bytes)
stack-mcache-inuse: 6.78KB (6944 bytes)
stack-mcache-sys: 16.00KB (16384 bytes)
other-sys: 4.58MB (4802459 bytes)
gc-sys: 251.55MB (263773240 bytes)
next-gc: when heap-alloc >= 100.19MB (105060944 bytes)
last-gc: 2020-08-14 20:54:01.063567774 +0800 CST
gc-pause-total: 982.706218ms
gc-pause: 17439
num-gc: 3484
enable-gc: true
debug-gc: false

剖析从下面的指标能够得出以下论断

  1. 以后正在应用的堆内存大抵是 60 多 M
  2. HeapReleased = 6.33 GB 返还给操作系统的物理内存的字节数是 6.33GB (
    HeapReleased 统计了从 idle
    span 中返还给操作系统,没有被从新获取的内存大小)

那问题就形象为:\为什么 HeapReleased 回升,RSS 没有降落?\

搜寻了一下有人踩过这个坑了,参考:https://zhuanlan.zhihu.com/p/…

这是因为 Go 底层用 mmap 申请的内存,会用 madvise 开释内存。具体见
go/src/runtime/mem~linux~.go 的代码。

madvise 将某段内存标记为不再应用时,有两种形式 MADV~DONTNEED~ 和
MADV~FREE~(通过标记参数传入):

  • MADV~DONTNEED 标记过的内存如果再次应用~,会触发缺页中断
  • MADV~FREE 标记过的内存~,内核会等到内存缓和时才会开释。在开释之前,这块内存仍然
    能够复用。这个个性从 linux 4.5 版本内核开始反对

显然,MADV~FREE 是一种用空间换工夫的优化~。

  • 在 Go 1.12 之前,linux 平台下 Go runtime
    中的 sysUnsed 应用 madvise(MADV~DONTNEED~)
  • 在 Go 1.12 之后,在 MADV~FREE 可用时会优先应用 MADVFREE~

具体见 https://github.com/golang/go/…

Go
1.12 之后,提供了一种形式强制回退应用 MADV~DONTNEED 的形式~,在执行程序前增加
GODEBUG=madvdontneed=1。具体见
https://github.com/golang/go/…

另外还有一个疑点:当初晓得问题呈现的条件是 Go \> 1.12 && Linux Kernel \>
4.5,然而 为什么之前阿里云没有呈现,零碎 8 月 10 号整体迁徙到 aws 呈现了?

考察发现

阿里云机器内核 4.4.0-105-generic,而 aws 机器内核
4.15.0-1054-aws,刚好合乎预期,能够解释。

==

补充:8 月 24 日

应用 GODEBUG=madvdontneed=1 强制回退应用
MADV~DONTNEED~,没有再呈现内存透露问题。内存稳固在 200MB 左右

退出移动版