一、逃逸分析
堆:一般来讲是人为手动进行管理,手动申请、分配、释放。一般所涉及的内存大小并不定,一般会存放较大的对象。另外其分配相对慢,涉及到的指令动作也相对多
栈:由编译器进行管理,自动申请、分配、释放。一般不会太大,我们常见的函数参数(不同平台允许存放的数量不同),局部变量等等都会存放在栈上
反编译为汇编代码: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