golang 栈、堆分配分析及CPU、内存性能情况 - 灬菜鸟灬

时间:2024-03-10 16:37:40

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