当前位置: 代码迷 >> 综合 >> pprof调试
  详细解决方案

pprof调试

热度:50   发布时间:2023-10-16 12:22:38.0

[TOC]

性能调优

在计算机性能调试领域里,profiling 是指对应用程序的画像,画像就是应用程序使用 CPU 和内存的情况。 Go语言是一个对性能特别看重的语言,因此语言中自带了 profiling 的库,这篇文章就要讲解怎么在 golang 中做 profiling。

go性能优化

  • cpu profile: 报告程序的cpu使用情况,按照一定频率去采集应用程序在cpu和寄存器上面的数据
  • mem profile(heap profile):报告程序的内存使用情况
  • block profiling:报告 goroutines 不在运行状态的情况,可以用来分析和查找死锁等性能瓶颈
  • goroutine profiling:报告 goroutines 的使用情况,有哪些 goroutine,它们的调用关系是怎样的

采集性能的包

Go语言内置了获取程序的运行数据的工具,包括以下两个标准库:

  • runtime/pprof:采集工具型应用运行数据进行分析
  • net/http/pprof:采集服务型应用运行数据进行分析

注意,我们只应该在性能测试的时候才在代码中引入pprof。

工具型应用(runtime/pprof)

如果你的应用程序是运行一段时间就结束退出类型。那么最好的办法是在应用退出的时候把 profiling 的报告保存到文件中,进行分析。对于这种情况,可以使用runtime/pprof库。 首先在代码中导入runtime/pprof工具:

import "runtime/pprof"

CPU性能分析

开启CPU性能分析:

pprof.StartCPUProfile(w io.Writer)

停止CPU性能分析:

pprof.StopCPUProfile()

应用执行结束后,就会生成一个文件,保存了我们的 CPU profiling 数据。得到采样数据之后,使用go tool pprof工具进行CPU性能分析。

内存性能优化

记录程序的堆栈信息

pprof.WriteHeapProfile(w io.Writer)

得到采样数据之后,使用go tool pprof工具进行内存性能分析。

go tool pprof默认是使用-inuse_space进行统计,还可以使用-inuse-objects查看分配对象的数量

服务型应用(net/http/pprof)

如果你的应用程序是一直运行的,比如 web 应用,那么可以使用net/http/pprof库,它能够在提供 HTTP 服务进行分析。

如果使用了默认的http.DefaultServeMux(通常是代码直接使用 http.ListenAndServe(“0.0.0.0:8000”, nil)),只需要在你的web server端代码中按如下方式导入net/http/pprof

import _ "net/http/pprof"

如果你使用自定义的 Mux,则需要手动注册一些路由规则:

r.HandleFunc("/debug/pprof/", pprof.Index)
r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
r.HandleFunc("/debug/pprof/profile", pprof.Profile)
r.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
r.HandleFunc("/debug/pprof/trace", pprof.Trace)

如果你使用的是gin框架,那么推荐使用"github.com/DeanThompson/ginpprof"

不管哪种方式,你的 HTTP 服务都会多出/debug/pprof endpoint,访问它会得到类似下面的内容:

go tool pprof命令

实例

CPU维度的profile数据

mem维度的profile数据

package mainimport ("flag""fmt""os""runtime/pprof""time"
)//实例代码
func logicCode() {var c chan intfor {select {case v := <-c: //阻塞fmt.Printf("recv from chan, value:%v\n", v)default:time.Sleep(time.Millisecond * 400)}}
}//采集数据
func main() {var isCPUPprof bool //是否开启cpu profile的标志位var isMemPprof bool // 是否开启内存 profile标志位//外部传入cpu、mem的参数flag.BoolVar(&isCPUPprof, "cpu", false, "turn cpu pprof on")flag.BoolVar(&isMemPprof, "mem", false, "turn mem pprof on")flag.Parse()// 如果开启了cpu pprof,那么就把cpu相关的记录写入cpu.pprof中if isCPUPprof {f1, err := os.Create("./cpu.pprof")if err != nil {fmt.Printf("create cpu pprof failed, err:%v\n", err)return}pprof.StartCPUProfile(f1) //开启CPU性能分析,往文件中记录cpu profile信息defer func() {pprof.StopCPUProfile() //停止CPU性能分析f1.Close()}()}for i := 0; i < 6; i++ {go logicCode()}time.Sleep(20 * time.Second)//如果开启了mem pprof 那么就把相关信息写入mem.pprof中if isMemPprof {f2, err := os.Create("./mem.pprof")if err != nil {fmt.Printf("create mem pprof failed, err:%v\n", err)return}pprof.WriteHeapProfile(f2)f2.Close()}
}