文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

生产环境 Go 程序内存泄露,用 Pprof 如何快速定位

2024-12-02 08:04

关注

比如查数据库时,有个查询条件在一定情况下应用不到,导致程序被迫持有一个超大的结果集,这样持续一段时间,执行相同任务的线程一多,就会造成内存泄露。

Golang 为我们提供了 pprof 工具。掌握之后,可以帮助排查程序的内存泄露问题,当然除了排查内存,它也能排查 CPU 占用过高,线程死锁的这些问题,不过这篇文章我们会聚焦在怎么用 pprof 排查程序的内存泄露问题。

Go 开发的系统中,怎么 添加 pprof 进行采样的步骤,在这里我就不再细说了,因为我之前的文章,对 pprof 的安装和使用做了详细的说明,文章链接我放在这里:

当然如果你想尝试点更智能的,让程序能自己监控自己,并在出现抖动的时候自己采样,Dump 出导致内存、CPU的问题调用栈信息,可以看一下下面两篇文章里我介绍的方法和实用的类库。

内存泄露该看哪个指标

pprof工具集,提供了Go程序内部多种性能指标的采样能力,我们常会用到的性能采样指标有这些:

上面 heap 和 allocs 是两个与内存相关的指标, allocs 指标会采样自程序启动所有对象的内存分配信息。一般是在想要分析哪些代码能优化提高效率时,查看的指标。针对查看内存泄露问题的分析,使用则的是 heap 指标里的采样信息。

Heap

pprof 的 heap 信息,是对堆中活跃对象的内存分配情况的采样。Go 里边哪些对象会被分配到堆上?一般概况就是,被多个函数引用的对象、全局变量、超过一定体积(32KB)的对象都会被分配到堆上,当然对于 Go 来说还会有其他的一些情况会让对象逃逸到堆上。

具体哪些变量会被分配到堆上、以及内存逃逸的事儿,就不多说了,想看详细情况的,看下面这两篇文章。

Heap 采样

要使用 pprof 获取 heap 指标的采样信息,一种情况是使用 "net/http/pprof" 包

import (
"net/http/pprof"
)

func main() {
http.HandleFunc("/debug/pprof/heap", pprof.Index)
......
http.ListenAndServe(":80", nil)
}

然后通过 HTTP 请求的方式获得

curl -sK -v https://example.com/debug/pprof/profile > heap.out

还有一种主要的方法是使用runtime.pprof 提供的方法,把采样信息保存到文件。

pprof.Lookup("heap").WriteTo(profile_file, 0)

关于这两个包的使用方式,以及怎么把信息采样到文件,上面介绍自动采样的文章里有详细的介绍,这里就不再花过多篇幅了。

下面进入文章的正题, 拿到采样文件后,怎么用 pprof 排查出代码哪里导致了内存泄露。

用 pprof 找出内存泄露的地方

pprof 在采样 heap 指标的信息时,使用的是 runtime.MemProfile 函数,该函数默认收集每个 512KB 已分配字节的分配信息。我们可以设置让 runtime.MemProfile 收集所有对象的信息,不过这会对程序的性能造成影响。

当我们拿到采样文件后,就可以通过 go tool pprof 将信息加载到一个交互模式的控制台中。

> go tool pprof heap.out

进入,交互式控制台后,一般会有如下的提示:

File: heap.out
Type: inuse_space
Time: Feb 1, 2022 at 10:11am (CST)
Entering interactive mode (type "help" for commands, "o" for options)

这里的 Type: inuse_space 指明了文件内采样信息的类型, Type 可能的值有:

接下来,介绍一个 pprof 交互式模式下的命令top,也可以是 topN,比如 top10。这个跟Linux 系统的 top 命令类似,输出 Top N 个最占用内存的函数。

(pprof) top10
Showing nodes accounting for 134.55MB, 92.16% of 145.99MB total
Dropped 60 nodes (cum <= 0.73MB)
Showing top 10 nodes out of 117
flat flat% sum% cum cum%
60.53MB 41.46% 41.46% 85.68MB 58.69% github.com/jinzhu/gorm.glob..func2
18.65MB 12.77% 54.24% 18.65MB 12.77% regexp.(*Regexp).Split
16.95MB 11.61% 65.84% 16.95MB 11.61% github.com/jinzhu/gorm.(*Scope).AddToVars
8.67MB 5.94% 71.78% 129.05MB 88.39% example.com/xxservice/dummy.GetLargeData
7.50MB 5.14% 82.63% 7.50MB 5.14% reflect.packEface
6.50MB 4.45% 87.08% 6.50MB 4.45% fmt.Sprintf
4MB 2.74% 89.82% 4MB 2.74% runtime.malg
1.91MB 1.31% 91.13% 1.91MB 1.31% strings.Replace
1.51MB 1.03% 92.16% 1.51MB 1.03% bytes.makeSlice

在这两个里边,最占用内存的前三是 gorm 库的一个方法,gorm 是个 ORM 库,但是导致它内存泄露的原因应该是后面一个有业务逻辑的代码,dummy.GetLargeData 方法。

在 top 指令输出的列表中,我们可以看到两个值,flat 和 cum。

此外 sum % 表示前面几行输出的 flat百分比之和, 比如上面第四行 sum% 列的值是, 71.78% 实际上就是它以及它上面三行输出的 flat% 的总和。

定位到导致内存泄露的函数后,后面要做的优化问题就是,深入函数内部,看哪里使用不当或者有逻辑上的疏忽,比如我开头举得那个查询条件在有些情况下应用不上的例子。

当然如果你想在函数内部再精确的定位到底是哪段代码导致的内存溢出,也是有办法的,这时候就需要用到 list 指令了。

list 指令可以列出函数内部,每一行代码运行时分配的内存(如果分析CPU的采样文件,则会显示CPU使用时间)

(pprof) list dummy.GetLargeData
Total: 814.62MB
ROUTINE ======================== dummy.GetLargeData in /home/xxx/xxx/xxx.go
814.62MB 814.62MB (flat, cum) 100% of Total
. . 20: }()
. . 21:
. . 22: tick := time.Tick(time.Second / 100)
. . 23: var buf []byte
. . 24: for range tick {
814.62MB 814.62MB 25: buf = append(buf, make([]byte, 1024*1024)...)
. . 26: }
. . 27:}
. . 28:

总结

这里把用 pprof 怎么排查程序的内存泄露做了个简单的总结,当然如果你们公司有条件上持续采样,或者我之前文章说的自动采样方案的话,最好还是用上,让机器帮我们做这些事情。

不过不管是用什么办法,最终只能是帮我们定位出来哪里造成了内存泄露,至于要怎么优化解决这个问题,还得具体情况具体分析,如果是一些业务逻辑实现上的问题,那就得跟团队商量一下实现方式,可能还会涉及到产品上的一些改动。

来源:网管叨bi叨内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯