go技能卡:利用pprof排查内存泄漏

浅言碎语

前几天在POC环境,我负责的一个项目的调度程序内存出现线性增长,由于我们的常驻内存程序限制最大为256MB,所以增长超过这个限制的时候就会被kill掉。

明明DEV, TEST两个环境都是正确的,为啥POC就出现异常了呢?正当我们焦头烂额的时候,想起来我之前在程序里面已经开启了pprof数据采集服务,最终我们通过pprof找到问题位置,排查发现有一位同学在for循环开启了context之后没有关闭掉,使得内存一直增长,添加闭包之后得以解决。

关于pprof

pprof是提供应用运行状态(CPU, 内存,Goroutine, 锁等)数据和可视化分析的工具。目前pprof提供了两种方式

  • runtime/pprof
  • net/http/pprof

其实net/http/pprof本内部也是使用runtime/pprof来实现,只不过是可以通过端口的方式暴露访问。本文主要讲述net/http/pprof的使用方法。参考net/http/pprof

使用

最简单的使用是在你的main函数里面导入net/http/pprof包,并监听一个端口号。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import (
    "io"
    "log"
    "net/http"
    _ "net/http/pprof"
)

func main() {

    helloHandler := func(w http.ResponseWriter, req *http.Request) {
        io.WriteString(w, "Hello, world!\n")
    }

    http.HandleFunc("/hello", helloHandler)
    log.Fatal(http.ListenAndServe(":8080"nil))
}

让后在浏览器中访问链接:http://127.0.0.1:8080/debug/pprof/可以看到:

下面讲述一下上面几个参数的意义

| 类型 | 描述 |
| — | — | — |
| allocs | 内存分配情况的采样信息 |
| blocks | 阻塞操作情况的采样信息 |
| cmdline | 显示程序启动命令及参数 |
| goroutine | 当前所有协程的堆栈信息 |
| heap | 堆上内存使用情况的采样信息 |
| mutex | 锁争用情况的采样信息 |
| profile | CPU 占用情况的采样信息 |
| threadcreate | 系统线程创建情况的采样信息 |
| trace | 程序运行跟踪信息 |

说实话上面的信息打开后可读性不高,满屏密密麻麻的字符,不仔细看根本没法找到需要的信息,此时我们可以使用go tool命令来查看自己需要的信息。

1
go tool http://127.0.0.1:8080/debug/pprof/指标

比如我们在cmd里面打开go tool pprof http://127.0.0.1:8080/debug/pprof/allocs,次数会进入待输入命令状态,如果想知道可以支持什么命令则可以输入help即可查看, 进一步如果想看该命令释放方法可以help 命令得到,比如下面输入help list之后:

通常情况下我们会使用top/top10/top20来查看当前指数程序占用排行。

如果我们需要查看具体占用位置,可以输入list 关键字,比如list StartCPUProfile:

此时我们就可以定位到问题了。

锦上添花

其实使用上面的方式我们已经定位到问题位置,但是命令行终究不够直观,如果提供一个文档或者网页能够把数据统计处理统计给我们,那岂不是妙哉,现饭还是很香的。我们只能想想,而大佬早已实现,其实pprof已经提供了网页方式浏览。我们只需要在上面的命令添加-web即可。但是如果你是第一次使用,则会出现以下问题:

其实是提示我们需要安装Graphviz,Graphviz是一个由AT&T实验室启动的开源工具包,用于绘制DOT语言脚本描述的图形。我们需要安装一下,(下载地址)[https://graphviz.org/download/]。

安装之后重新执行go tool pprof -web http://127.0.0.1:8080/debug/pprof/allocs

上面其实是在浏览器中打开文件,其实还有更好的一种方式,利用pprof起一个服务,可以实时看到指标信息, 执行go tool pprof -web http://127.0.0.1:8080/debug/pprof/allocs:

你可以选择上面的TOP查看排行情况:

你还可以选择Peek查看调用详情:

其实还有很多功能,比如查看火焰图,查看当前数据和累计数据等。