安装 Graphviz

分享到:

安装 Graphviz

深度解密Go语言之 pprof

深度解密Go语言之 pprof

https://github.com/golang/go/wiki/Performance

gops 分析机器上运行了哪些go进程 https://shockerli.net/post/golang-tool-gops/

godebug:一个跨平台的Go程序调试工具 go tool trace

查看运行时间,详细 /usr/bin/time -v go run test2.go

go tool pprof -http=:1234 http://10.244.28.10:8080/debug/pprof/profile?seconds=30 go tool pprof -http=:1234 http://10.244.28.10:8080/debug/pprof/allocs?seconds=30

堆的信息

1go tool pprof -http :9090 http://ip:port/debug/pprof/heap

cpu(CPU Profiling): $HOST/debug/pprof/profile,默认进行 30s 的 CPU Profiling,得到一个分析用的 profile 文件 block(Block Profiling):$HOST/debug/pprof/block,查看导致阻塞同步的堆栈跟踪 goroutine:$HOST/debug/pprof/goroutine,查看当前所有运行的 goroutines 堆栈跟踪 heap(Memory Profiling): $HOST/debug/pprof/heap,查看活动对象的内存分配情况 mutex(Mutex Profiling):$HOST/debug/pprof/mutex,查看导致互斥锁的竞争持有者的堆栈跟踪 threadcreate:$HOST/debug/pprof/threadcreate,查看创建新OS线程的堆栈跟踪

pprof可以比较两个时间点的分配的内存的差值

  1. 首先确保你已经配置了 pprof 的 http 路径, 可以访问http://ip:port/debug/pprof/查看(如果你没有修改默认的 pprof 路径)

  2. 导出时间点 1的堆的 profile: curl -s http://127.0.0.1:8080/debug/pprof/heap > base.heap, 我们把它作为基准点

  3. 喝杯茶,等待一段时间后导出时间点 2的堆的 profile: curl -s http://127.0.0.1:8080/debug/pprof/heap > current.heap

  4. 现在你就可以比较这两个时间点的堆的差异了: go tool pprof --base base.heap current.heap

  5. 使用web命令会生成一个 SVG 文件,可能你需要使用浏览器打开它。 或者你直接使用命令打开 web 界面: go tool pprof --http :9090 --base base.heap current.heap。

通过比较差值,就容易看到哪些地方产生的内存"残留"的比较多,没有被内存释放,极有可能是内存泄漏的点。

go tool pprof -inuse_space http://127.0.0.1:9999/debug/pprof/heap。输入top10可以看出前十占用内存情况,这里我是直接输入png导出图片来查看,以便以后比较。还有两个参数可以选择,-inuse_space顾名思义是正在使用的内存,-alloc_space是已经分配的内存,本次我是一直用-inuse_space进行分析。

go tool pprof http://localhost:6060/debug/pprof/profile?seconds=60 执行该命令后,需等待 60 秒(可调整 seconds 的值),pprof 会进行 CPU Profiling。结束后将默认进入 pprof 的交互式命令模式,可以对分析的结果进行查看或导出。

go tool pprof -svg http://localhost:8080/debug/pprof/heap > cpu.svg

安装 Graphviz

https://graphviz.gitlab.io/_pages/Download/Download_windows.html

go tool pprof --http :9090 http://localhost:8080/debug/pprof/heap

方法一: $ go tool pprof -http=:8080 cpu.prof 方法二: $ go tool pprof cpu.prof $ (pprof) web

另一种可视化数据的方法是火焰图,需手动安装原生 PProf 工具:

(1) 安装 PProf

$ go get -u github.com/google/pprof (2) 启动 PProf 可视化界面:

$ pprof -http=:8080 cpu.prof (3) 查看 PProf 可视化界面

打开 PProf 的可视化界面时,你会明显发现比官方工具链的 PProf 精致一些,并且多了 Flame Graph(火焰图)

它就是本次的目标之一,它的最大优点是动态的。调用顺序由上到下(A -> B -> C -> D),每一块代表一个函数,越大代表占用 CPU 的时间更长。同时它也支持点击块深入进行分析!

go tool trace trace.out

1	f, _ := os.Create("trace.out")
2	defer f.Close()
3	trace.Start(f)
4	defer trace.Stop()

也可以写入文件

golang 的性能分析库在 runtime/pprof 里,主要提供下面几个接口

// 堆栈分析 func WriteHeapProfile(w io.Writer) error // cpu分析 func StartCPUProfile(w io.Writer) error

方法1

 1var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
 2
 3func main() {
 4    flag.Parse()
 5    if *cpuprofile != "" {
 6        f, err := os.Create(*cpuprofile)
 7        if err != nil {
 8            log.Fatal(err)
 9        }
10        pprof.StartCPUProfile(f)
11        defer pprof.StopCPUProfile()
12    }
1314

https://github.com/hatlonely/easygolang/blob/master/pprof/pprof.go

参考

go tool pprof 使用介绍 :https://segmentfault.com/a/1190000016412013

Go 内存监控介绍:https://golang.org/src/runtime/mstats.go

Go 内存优化介绍:https://blog.golang.org/profiling-go-programs

高性能Go服务内存分配:https://segment.com/blog/allocation-efficiency-in-high-performance-go-services

Go stack 优化分析:https://studygolang.com/articles/10597

Go内存泄漏?不是那么简单! https://colobu.com/2019/08/28/go-memory-leak-i-dont-think-so/

内存不归还系统

 1package main
 2
 3import (
 4	"fmt"
 5	"runtime"
 6	"runtime/debug"
 7	"time"
 8)
 9
10func main() {
11
12	go func() {
13		var a []int
14		for i := 0; i < 2000; i++ {
15			a = make([]int, i*100000)
16		}
17		a = nil
18		fmt.Printf("%v\n", a)
19	}()
20
21	go func() {
22		for {
23			m := runtime.MemStats{}
24			d := debug.GCStats{}
25			runtime.ReadMemStats(&m)
26			debug.ReadGCStats(&d)
27			fmt.Printf("%v\t%v\t%v\n", d.NumGC, m.HeapIdle/1024/1024, m.HeapInuse/1024/1024)
28			time.Sleep(time.Second)
29		}
30	}()
31	for {
32		runtime.GC()
33		time.Sleep(time.Second)
34	}
35
36}
 1package main
 2
 3import (
 4    "fmt"
 5    "runtime"
 6    "runtime/debug"
 7    "time"
 8)
 9
10func main() {
11    var a []int
12    for i := 0; i < 200; i++ {
13        a = make([]int, i*100000)
14    }
15    a = nil
16    fmt.Printf("%v\n", a)
17    for {
18        m := runtime.MemStats{}
19        d := debug.GCStats{}
20        runtime.ReadMemStats(&m)
21        debug.ReadGCStats(&d)
22        fmt.Printf("%v\t%v\t%v\n", d.NumGC, m.HeapIdle/1024/1024, m.HeapInuse/1024/1024)
23        time.Sleep(time.Second)
24    }
25}

https://www.cnblogs.com/luckcs/articles/4107647.html

 1package main
 2 
 3import (  
 4    "fmt" 
 5    "math/rand" 
 6    "runtime" 
 7    "time"
 8)  
 9 
10func makeBuffer() []byte {  
11    return make([]byte, rand.Intn(5000000)+5000000)  
12}
13 
14func main() {  
15    pool := make([][]byte, 20)
16 
17    var m runtime.MemStats  
18    makes := 0  
19    for {  
20        b := makeBuffer()
21        makes += 1
22        i := rand.Intn(len(pool))
23        pool[i] = b
24 
25        time.Sleep(time.Second)
26 
27        bytes := 0
28 
29        for i := 0; i < len(pool); i++ {
30            if pool[i] != nil {
31                bytes += len(pool[i])
32            }
33        }
34 
35        runtime.ReadMemStats(&m)
36        fmt.Printf("%d,%d,%d,%d,%d,%d\n", m.HeapSys, bytes, m.HeapAlloc,
37            m.HeapIdle, m.HeapReleased, makes)
38    }
39}