目录

概要

pprof的作用

使用方式

交互式常用命令

以profile为例,其余的指标也是用一样的命令

Top N

List func

Traces

web func

Base

Debug=[num]

排查内存泄漏

内存逃逸

内存泄漏的方式

如何判断goroutine泄露


概要

一般而言,性能分析可以从三个层次来考虑:应用层、系统层、代码层。

应用层主要是梳理业务方的使用方式,让他们更合理地使用,在满足使用方需求的前提下,减少无意义的调用;系统层关注服务的架构,例如增加一层缓存;代码层则关心函数的执行效率,例如使用效率更高的开方算法等。

Profiling 是指在程序执行过程中,收集能够反映程序执行状态的数据。在软件工程中,性能分析(performance analysis,也称为 profiling),是以收集程序运行时信息为手段研究程序行为的分析方法,是一种动态程序分析的方法。

Go 语言自带的 pprof 库就可以分析程序的运行情况,并且提供可视化的功能。它包含两个相关的库:

  • runtime/pprof
    对于只跑一次的程序,例如每天只跑一次的离线预处理程序,调用 pprof 包提供的函数,手动开启性能数据采集。
  • net/http/pprof
    对于在线服务,对于一个 HTTP Server,访问 pprof 提供的 HTTP 接口,获得性能数据。当然,实际上这里底层也是调用的 runtime/pprof 提供的函数,封装成接口对外提供网络访问。

pprof的作用

allocs 和 heap 采样的信息一致,不过前者是所有对象的内存分配,而 heap 则是活跃对象的内存分配。

  • 当 CPU 性能分析启用后,Go runtime 会每 10ms 就暂停一下,记录当前运行的 goroutine 的调用堆栈及相关数据。当性能分析数据保存到硬盘后,我们就可以分析代码中的热点了。
  • 内存性能分析则是在堆(Heap and alloc)分配的时候,记录一下调用堆栈。默认情况下,是每 1000 次分配,取样一次,这个数值可以改变。栈(Stack)分配 由于会随时释放,因此不会被内存分析所记录。由于内存分析是取样方式,并且也因为其记录的是分配内存,而不是使用内存。因此使用内存性能分析工具来准确判断程序具体的内存使用是比较困难的。heap 主要记录的是当前活着的(没有被gc)的堆中的内存占用,alloc主要记录一段时间内分配的堆中内存(即使被释放也会记录进去)。
  • 阻塞(mutex and block)分析是一个很独特的分析,它有点儿类似于 CPU 性能分析,但是它所记录的是 goroutine 等待资源所花的时间。阻塞分析对分析程序并发瓶颈非常有帮助,阻塞性能分析可以显示出什么时候出现了大批的 goroutine 被阻塞了。阻塞性能分析是特殊的分析工具,在排除 CPU 和内存瓶颈前,不应该用它来分析。

使用方式

当服务集成了pprof功能后,我们可以使用浏览器访问它。如http://localhost:6060/debug/pprof/

点击相应的子链接可以将prof文件下载到本地,profile默认会等待30s以便收集数据,其它的不需要等待。

另一种方式是使用工具链直接下载,如 go tool pprof http://localhost:6060/debug/pprof/block

然后我们可以使用以下命令进入交互式对话: go tool pprof [download_file]

交互式常用命令

以profile为例,其余的指标也是用一样的命令

Top N

打印最耗时的N个函数

List func

打印该函数每行代码的耗时情况

Traces

打印采样期间所有的调用栈,每一次采样的时间为10ms,一次采样为一个。以下为一个sample

      20ms   github.com/yuin/gopher-lua.(*allocator).LNumber2Igithub.com/yuin/gopher-lua.(*registry).SetNumbergithub.com/yuin/gopher-lua.opArithgithub.com/yuin/gopher-lua.mainLoopgithub.com/yuin/gopher-lua.(*LState).callRgithub.com/yuin/gopher-lua.(*LState).Callgithub.com/yuin/gopher-lua.(*LState).PCallgithub.com/yuin/gopher-lua.(*LState).CallByParamgit.xiaojukeji.com/geomining/nemo/src/ilua.(*LState).CallByParamgit.xiaojukeji.com/geomining/nemo/src/activity.(*Activity).QueryDetail
git.xiaojukeji.com/geomining/nemo/src/controller/fetchactdetailctr.(*FetchActDetailController).ServeHTTPnet/http.(*ServeMux).ServeHTTPgithub.com/rs/cors.(*Cors).Handler.func1net/http.HandlerFunc.ServeHTTPnet/http.serverHandler.ServeHTTPnet/http.(*conn).serve

web func

聚焦到该函数,打印上下游调用链(图)

Base

使用base能够对比两个profile文件的差别,就像diff命令一样显示出增加和减少的变化

Debug=[num]

在url后面添加debug=[num]的参数,可以打印出额外的信息。

以goroutine为例,Debug=1时的打印信息如下:

32015 @ 0x42e15a 0x42e20e 0x40534b 0x4050e5 0x6d8559 0x6d831b 0x45abe1
#    0x6d8558    main.alloc2.func1+0xf8  /home/ubuntu/heap/leak_demo.go:53
#    0x6d831a    main.alloc2+0x2a    /home/ubuntu/heap/leak_demo.go:54解释
1.  goroutine profile: total 32023:32023是goroutine的总数量,
2.  32015 @ 0x42e15a 0x42e20e 0x40534b 0x4050e5 …:32015代表当前有32015个goroutine运行这个调用栈,并且停在相同位置,@后面的十六进制,现在用不到这个数据,所以暂不深究了。
3.  下面是当前goroutine的调用栈,列出了函数和所在文件的行数,这个行数对定位很有帮助,如下:
32015 @ 0x42e15a 0x42e20e 0x40534b 0x4050e5 0x6d8559 0x6d831b 0x45abe1
#    0x6d8558    main.alloc2.func1+0xf8  /home/ubuntu/heap/leak_demo.go:53
#    0x6d831a    main.alloc2+0x2a    /home/ubuntu/heap/leak_demo.go:54
根据上面的提示,就能判断32015个goroutine运行到leak_demo.go的53行:

Debug=2时的打印信息如下:

goroutine 20 [chan send, 2 minutes]:
main.alloc2.func1(0xc42015e060)/home/ubuntu/heap/leak_demo.go:53 +0xf9  // 这
main.alloc2(0xc42015e060)/home/ubuntu/heap/leak_demo.go:54 +0x2b
created by main.alloc1/home/ubuntu/heap/leak_demo.go:42 +0x3f解释
1.  goroutine 20 [chan send, 2 minutes]:20是goroutine id,[]中是当前goroutine的状态,阻塞在写channel,并且阻塞了2分钟,长时间运行的系统,你能看到阻塞时间更长的情况。
2.  同时,也可以看到调用栈,看当前执行停到哪了:leak_demo.go的53行,

排查内存泄漏

内存逃逸

Go 语言通过逃逸分析会将尽可能多的对象分配到栈上,以使程序可以运行地更快。

这里有个小插曲,你可尝试一下将 16 * constant.Mi 修改成一个较小的值,重新编译运行,会发现并不会引起频繁 GC,原因是在 golang 里,对象是使用堆内存还是栈内存,由编译器进行逃逸分析并决定,如果对象不会逃逸,便可在使用栈内存,但总有意外,就是对象的尺寸过大时,便不得不使用堆内存。所以这里设置申请 16 MiB 的内存就是为了避免编译器直接在栈上分配,如果那样得话就不会涉及到 GC 了。

内存泄漏的方式

如果你启动了1个goroutine,但并没有符合预期的退出,直到程序结束,此goroutine才退出,这种情况就是goroutine泄露。

  1. goroutine本身的栈所占用的空间造成内存泄露,如未关闭已打开的文件,网络句柄等。
  2. goroutine中的变量所占用的堆内存导致堆内存泄露,这一部分是能通过heap profile体现出来的。

解决goroutine泄露的根本方法是,程序员自己需要知道goroutine产生的个数和何时退出。

如何判断goroutine泄露

判断依据:在节点正常运行的情况下,隔一段时间获取goroutine的数量,如果后面获取的那次,某些goroutine比前一次多,如果多获取几次,是持续增长的,就极有可能是goroutine泄露。

Golang pprof简介相关推荐

  1. 白话 Golang pprof

    文章目录 0.前言 1.什么是 pprof 2.pprof 的作用是什么 3.pprof 的使用模式 4.安装 Graphviz 4.应用程序性能分析 4.1 CPU 性能分析 4.2 内存性能分析 ...

  2. golang pprof

    这里填写标题 1. golang pprof 1.1. pprof 实例 2. go tool 2.1. `--inuse/alloc_space` `--inuse/alloc_objects` 区 ...

  3. 使用golang pprof进行性能分析

    golang pprof,说实话自己还一次都没有实际操作过. 最近这几天的需求恰好需要分析下一个看似很简单的服务,内存配置上限是900m,最终在大量并发的时候出现oom的情况. 代码准备 首先代码需要 ...

  4. Golang(1)Golang语言简介

    Golang(1)Golang语言简介 Golang(2)win10下安装Go语言 Golang(3)CentOS7系统安装Go语言 一.Golang的学习方向 (1)区块链研发工程师 (2)Go服务 ...

  5. Golang 特性简介

    by sheepbao 主要大概介绍go语言的历史和特性,简单的入门. 来历 很久以前,有一个IT公司,这公司有个传统,允许员工拥有20%自由时间来开发实验性项目.在2007的某一天,公司的几个大牛, ...

  6. Golang(1)-简介及特性

    文章目录 一.Golang简介 1.1.什么是Golang 1.2.使用Golang完成的著名项目 1.3.Golang的特性 二.Golang的特性概述 2.1.自动垃圾回收 2.2.丰富的内置类型 ...

  7. golang pprof工具

    pprof工具 pprof是什么 pprof是分析和显示性能相关数据的工具 pprof读取profile.proto格式的分析抽样集合数据,同时创建报告来展现和帮助分析数据,它能创建包括文本和图型报告 ...

  8. Golang:简介、基本语法、函数、defer、Test功能

    春招找实习告一段落了,好长时间没更CSDN的博客,期间写的一些笔记用 typora + git 直接推到github里面了,就没在CSDN里再发了,我的github:https://github.co ...

  9. Golang pprof 使用

    目录 什么是 Profile? 两种收集方式 工具型应用 服务型应用 go tool ppof 获取和分析 profile 数据 终端 可视化 什么是 Profile? 在计算机性能调试领域里,pro ...

最新文章

  1. python 因果推断_KDD 2018:微软推出用于因果推断的Python库
  2. linux keepalived 脚本,Linux下 keepalived 的安装和配置
  3. python File write()方法
  4. 猎豹浏览器怎么收藏网页 网页收藏方法简述
  5. SpringBoot入门教程
  6. 400集python入门到精通_2020年最强Python学习路线+教程,400集带你从入门到精通
  7. 转行学AI,如何选择适合的方向
  8. 女生做产品经理好吗_谁说女生不适合做产品经理?
  9. android handler2--消息队列源码解析
  10. 1061. Dating (20)-PAT甲级真题
  11. python计算圆锥体积和表面积_圆柱与圆锥体积与表面积计算
  12. 如何将live stream发布到Youtube
  13. 解决Xcode couldn‘t find any iOS App Development provisioning profiles matching ‘com.facebook.WebDriver
  14. 基于vue技术栈制作自己的简历网站问题总结篇(入门vue基础项目)
  15. vue的SEO优化——预渲染后路由+点击事件失效问题解决
  16. atoi(s)函数用法 1
  17. 为什么数组名取地址和数组名的取值一样
  18. Python中使用Scrapy爬虫抓取上海链家房价信息
  19. NVT平台定时器的使用
  20. python matplotlib 绘制二维数据中某些列到折线图,没有线的解决方法

热门文章

  1. jQuery下(2nd)
  2. 细说;(function ($, undefined){ })(jQuery); 的使用
  3. FPGA Verilog HDL 系列实例--------顺序脉冲发生器
  4. visual Studio Code(VS code)软件中HTML超级好用的一个插件 liveserver,vs code浏览网页
  5. Android AOA协议Android端 流程总结
  6. 3分钟教会你用KaTeX在csdn博客中编辑数学公式
  7. 4D毫米波雷达硬件系统架构
  8. Linux 入门第一节
  9. 东大金智ARM工控主板助力构建新型智慧城市
  10. queue容器常用接口