zl程序教程

您现在的位置是:首页 >  其他

当前栏目

【博客544】golang pprof性能调试:寻找memory瓶颈

博客调试性能Golang 寻找 memory 瓶颈
2023-09-14 09:12:53 时间

golang pprof性能调试:寻找memory瓶颈

1、前置

pprof的使用与输出列解析看姐妹篇:golang pprof性能调试:寻找cpu瓶颈

2、引入pprof到程序中,以调试memory瓶颈

给程序加入:

import _ "net/http/pprof"

go func() {
	  http.ListenAndServe("0.0.0.0:9999", nil)
}()

示例:随机拼接字符串

package main

import (
	"math/rand"
	"net/http"
	_ "net/http/pprof"
)

const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

func randomString(n int) string {
	b := make([]byte, n)
	for i := range b {
		b[i] = letterBytes[rand.Intn(len(letterBytes))]
	}
	return string(b)
}

func concat(n int) string {
	s := ""
	for i := 0; i < n; i++ {
		s += randomString(n)
	}
	return s
}

func main() {
	go func() {
		http.ListenAndServe("0.0.0.0:9999", nil)
	}()

	for {
		concat(100)
	}
}

3、pprof命令行交互式查看程序最消耗memory的地方

1、启动上述程序:

go run main.go

2、访问pprof暴露的memory debug api接口,收集30s内的memory数据:

go tool pprof http://localhost:9999/debug/pprof/heap\?seconds\=30

3、在交互命令中,使用top,list来查看最消耗memory的地方

go tool pprof http://localhost:9999/debug/pprof/heap\?seconds\=30
Fetching profile over HTTP from http://localhost:9999/debug/pprof/heap?seconds=30
Saved profile in /Users/zejia.lu/pprof/pprof.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz
Type: inuse_space
Time: Nov 27, 2022 at 12:40pm (CST)
Duration: 30s, Total samples = 1MB
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing nodes accounting for -1026.68kB, 100% of 1026.68kB total
      flat  flat%   sum%        cum   cum%
  514.63kB 50.13% 50.13% -1026.68kB   100%  main.concat
  512.05kB 49.87%   100%  -512.05kB 49.87%  main.randomString
         0     0%   100% -1026.68kB   100%  main.main
         0     0%   100% -1026.68kB   100%  runtime.main
(pprof) list main.randomString
Total: 1MB
ROUTINE ======================== main.randomString in /Users/zejia.lu/memory_pprof/main.go
 512.05kB  512.05kB (flat, cum) 49.87% of Total
         .          .     11:func randomString(n int) string {
         .          .     12:	b := make([]byte, n)
         .          .     13:	for i := range b {
         .          .     14:		b[i] = letterBytes[rand.Intn(len(letterBytes))]
         .          .     15:	}
 512.05kB  512.05kB     16:	return string(b)
         .          .     17:}
         .          .     18:
         .          .     19:func concat(n int) string {
         .          .     20:	s := ""
         .          .     21:	for i := 0; i < n; i++ {

4、pprof ui方式查看程序最消耗memory的地方

1、调试时指定通过ui方式查看,ui地址为9900端口,要调试的服务暴露的pprof端口为9999:

go tool pprof -http=":9900" http://localhost:9999/debug/pprof/heap  -inuse_objects

2、访问9900端口查看ui界面进行可视化调试:

查看最消耗memory的地方:可以看到我们的concat逻辑函数就是memoory高消耗的地方
在这里插入图片描述
在这里插入图片描述

5、pprof ui方式查看memory消耗拓扑图

在这里插入图片描述

6、pprof ui方式查看memory消耗火焰图

在这里插入图片描述
在这里插入图片描述

7、查看其它类型的memroy,上述例子查看的是:inuse_space

inuse_space — 已分配但尚未释放的内存空间
inuse_objects——已分配但尚未释放的对象数量
alloc_space — 分配的内存总量(已释放的也会统计)
alloc_objects — 分配的对象总数(无论是否释放)

8、查看所有曾经申请过的内存总量

go tool pprof -http=":9900" http://localhost:9999/debug/pprof/allocs

结果:
在这里插入图片描述

9、如何调试其它方面的内容:

查看程序暴露的/debug/pprof/ api

http://127.0.0.1:9999/debug/pprof/

查看有哪些方面的调试内容:
在这里插入图片描述

常用调试示例:

# 获取30秒的CPU profiling
curl -o cpu.bin http://localhost:6060/debug/pprof/profile

# 获取5秒的执行跟踪(有一定性能影响)
curl -o trace.bin http://localhost:6060/debug/pprof/trace?seconds=5

# 获取内存使用的profile
curl -o heap.bin http://localhost:6060/debug/pprof/heap

# 获取正在运行的goroutines列表
curl -o goroutines.txt http://localhost:6060/debug/pprof/goroutine?debug=2

# 获取被blocking的goroutine列表
curl -o goroutines-blocking.txt http://localhost:6060/debug/pprof/block

如何分析火焰图

火焰图的调用顺序从下到上,每个方块代表一个函数,它上面一层表示这个函数会调用哪些函数,方块的大小代表了占用 CPU 使用时长长短。