golang 栈、堆分配分析及CPU、内存性能情况
一、逃逸分析
堆:一般来讲是人为手动进行管理,手动申请、分配、释放。一般所涉及的内存大小并不定,一般会存放较大的对象。另外其分配相对慢,涉及到的指令动作也相对多
栈:由编译器进行管理,自动申请、分配、释放。一般不会太大,我们常见的函数参数(不同平台允许存放的数量不同),局部变量等等都会存放在栈上
反编译为汇编代码:go tool compile -S main.go
栈、堆逃逸分析:go build -gcflags \'-m -l\' main.go
二、CPU、内存性能情况
1、time go run main.go
real 0m0.843s //从程序开始到结束,实际度过的时间;
user 0m0.216s //程序在用户态度过的时间;
sys 0m0.389s //程序在内核态度过的时间
2、/usr/bin/time -v go run test2.go
3、调用 runtime
中的 ReadMemStats()
方法获得内存信息,然后通过 log
打印出来。
package main import ( "log" "runtime" "time" ) func readMemStats() { var ms runtime.MemStats runtime.ReadMemStats(&ms) log.Printf(" ===> Alloc:%d(bytes) HeapIdle:%d(bytes) HeapReleased:%d(bytes)", ms.Alloc, ms.HeapIdle, ms.HeapReleased) } func test() { //slice 会动态扩容,用slice来做堆内存申请 container := make([]int, 8) log.Println(" ===> loop begin.") for i := 0; i < 32*1000*1000; i++ { container = append(container, i) if ( i == 16*1000*1000) { readMemStats() } } log.Println(" ===> loop end.") } func main() { log.Println(" ===> [Start].") readMemStats() test() readMemStats() log.Println(" ===> [force gc].") runtime.GC() //强制调用gc回收 log.Println(" ===> [Done].") readMemStats() go func() { for { readMemStats() time.Sleep(10 * time.Second) } }() time.Sleep(3600 * time.Second) //睡眠,保持程序不退出 }
4、pprof网页监控
package main import ( "log" "runtime" "time" "net/http" _ "net/http/pprof" ) func readMemStats() { var ms runtime.MemStats runtime.ReadMemStats(&ms) log.Printf(" ===> Alloc:%d(bytes) HeapIdle:%d(bytes) HeapReleased:%d(bytes)", ms.Alloc, ms.HeapIdle, ms.HeapReleased) } func test() { //slice 会动态扩容,用slice来做堆内存申请 container := make([]int, 8) log.Println(" ===> loop begin.") for i := 0; i < 32*1000*1000; i++ { container = append(container, i) if ( i == 16*1000*1000) { readMemStats() } } log.Println(" ===> loop end.") } func main() { //启动pprof go func() { log.Println(http.ListenAndServe("0.0.0.0:10000", nil)) }() log.Println(" ===> [Start].") readMemStats() test() readMemStats() log.Println(" ===> [force gc].") runtime.GC() //强制调用gc回收 log.Println(" ===> [Done].") readMemStats() go func() { for { readMemStats() time.Sleep(10 * time.Second) } }() time.Sleep(3600 * time.Second) //睡眠,保持程序不退出 }
记录了目前的内存情况:http://127.0.0.1:10000/debug/pprof/heap?debug=1
记录了目前的CPU情况:http://127.0.0.1:10000/debug/pprof/
5、gin使用pprof
5.1 安装:go get https://github.com/gin-contrib/pprof
5.2 在main.go写入监控:
package main import ( "github.com/gin-contrib/pprof" "github.com/gin-gonic/gin" ) func main() { s := gin.Default() // 方式一:性能 pprof.Register(s) // 方式二:性能 - 授权访问 a := s.Group("/admin", gin.BasicAuth(gin.Accounts{"root": "888000"})) pprof.RouteRegister(a) s.Run(":8080") }
5.3 web访问:http://127.0.01:8080/admin/debug/pprof/
5.4 页面参数:
类型 | 描述 | 备注 |
---|---|---|
allocs | 内存分配情况的采样信息 | 可以用浏览器打开, 但可读性不高 |
blocks | 阻塞操作情况的采样信息 | 可以用浏览器打开, 但可读性不高 |
cmdline | 显示程序启动命令及参数 | 可以用浏览器打开 |
goroutine | 当前所有协程的堆栈信息 | 可以用浏览器打开, 但可读性不高 |
heap | 堆上内存使用情况的采样信息 | 可以用浏览器打开, 但可读性不高 |
mutex | 锁争用情况的采样信息 | 可以用浏览器打开, 但可读性不高 |
profile | CPU 占用情况的采样信息, 持续 30s | 浏览器打开会下载文件 |
threadcreate | 系统线程创建情况的采样信息 | 可以用浏览器打开, 但可读性不高 |
trace | 程序运行跟踪信息 | 浏览器打开会下载文件 |
5.5 终端交互命令:
- go tool pprof http://localhost:8080/debug/pprof/profile?seconds=60
输入 top10
项 | 说明 |
---|---|
flat | 给定函数上运行耗时 |
flat% | 同上的 CPU 运行耗时总比例 |
sum% | 给定函数累积使用 CPU 总比例 |
cum | 当前函数加上它之上的调用运行总耗时 |
cum% | 同上的 CPU 运行耗时总比例 |
-
go tool pprof http://localhost:8080/debug/pprof/heap
type 类型
项 | 说明 |
---|---|
inuse_space | 分析应用程序的常驻内存占用情况 |
alloc_objects | 分析应用程序的内存临时分配情况 |
-
go tool pprof http://localhost:8080/debug/pprof/block
-
go tool pprof http://localhost:8080/debug/pprof/mutex
5.6 可视化界面
启动方式一:go tool pprof -http=:8080 cpu.prof
启动方式二:go tool pprof cpu.prof