• 爱上开源之golang入门至实战第三章-性能分析-Heap


    Heap Memory

    Heap: A sampling of memory allocations of live objects. You can specify the gc GET parameter to run GC before taking the heap sample.

    添加gc这个parameter到get的url里, 可以在采样之前强制执行一次GC后,再进行采样;来之pprof.go(net/http/pprof.go)源码

    Heap的手工埋点

    如果是Run over Once的工具包,需要自己进行手工埋点的话, 大致的方法和上面CPU Profiling的埋点方式一致,只是需要调用不同的pprof的方法即可; 对于Heap埋点,调用pprof.WriteHeapProfile

    1. if err := pprof.WriteHeapProfile(f1); err != nil {
    2. panic("could not start heap-1 profile: ")
    3. }

    pprof工具Heap分析

    运行命令

    go tool pprof http://localhost:8999/debug/pprof/heap

     使用top命令,查看内存占用最多的地方

    Top命令的结果,列表出了在采样的快照,发生的程序中各种函数调用过程中内存占用最多的函数调用;

    其中每一行都表示一个采用到的函数调用,

    每类都对应着采集到的数据分析; 列的参照如下

    flat:函数在调用中内存占用数量

    flat%:函数在调用中内存占用的百分比

    sum%:所有函数累加使用内存的比例,即所有flat%的总和

    cum: 函数以及子函数运行所使用内存,应该大于等于flat

    cum%: 函数以及子函数运行所使用内存的比例,应该大于等于flat%

    函数的名字

    这里可以看到调用现在内存占用最多的占用内存60MB, 占所有内存总量的99.15%,main.startHttpServer.func3, 这个函数的调用占用的内存基本上就是所有的内存, 这个函数究竟做了哪些动作,导致内存的占用, 我们可以在pprof里运行list命令, 进一步进行分析

    使用pprof命令:list 函数名。 可以用pprof分析函数中的哪一行导致的内存占用

    1. (pprof) list func3
    2. Total: 60.52MB
    3. ROUTINE ======================== main.startHttpServer.func3 in E:\WORK\PROJECT\git\go\gohutool\boot4go-docker-ui\docker.ui.go
    4.      60MB       60MB (flat, cum) 99.15% of Total
    5.         .          .    180:
    6.         .          .    181:           if len(testPool) >= POOLSIZE {
    7.         .          .    182:                   testPool = testPool[0:0]
    8.         .          .    183:           }
    9.         .          .    184:
    10.      60MB       60MB    185:           testPool = append(testPool, make([]byte, SIZE))
    11.         .          .    186:
    12.         .          .    187:           return nil
    13.         .          .    188:   })
    14.         .          .    189:
    15.         .          .    190:   router.Any("/debug/pprof/*", func(ctx *routing.Context) error {

     
    

    通过这个命令,可以直接追击到源代码的行数,从而进行仔细的调用过程分析

    代码185行: make([]byte, SIZE) 进行了内存的操作, 这里的60M全部这里进行操作的。

    使用图形化web命令进行分析

    在pprof的交互模式里输入web命令

    使用tree命令查看

    1. (pprof) tree
    2. Showing nodes accounting for 206.50MB, 99.28% of 208MB total
    3. Dropped 15 nodes (cum <= 1.04MB)
    4. ----------------------------------------------------------+-------------
    5.      flat  flat%   sum%        cum   cum%   calls calls% + context
    6. ----------------------------------------------------------+-------------
    7.                                             204MB   100% |   github.com/qiangxue/fasthttp-routing.(*Context).Next
    8.     204MB 98.08% 98.08%      204MB 98.08%                | main.startHttpServer.func3
    9. ----------------------------------------------------------+-------------
    10.                                            2.50MB   100% |   runtime.newm
    11.    2.50MB  1.20% 99.28%     2.50MB  1.20%                | runtime.allocm
    12. ----------------------------------------------------------+-------------
    13.                                             204MB   100% |   github.com/qiangxue/fasthttp-routing.(*Router).HandleRequest
    14.         0     0% 99.28%      204MB 98.08%                | github.com/qiangxue/fasthttp-routing.(*Context).Next
    15.                                             204MB   100% |   main.startHttpServer.func3
    16. ----------------------------------------------------------+-------------
    17.                                             204MB   100% |   main.startHttpServer.func8
    18.         0     0% 99.28%      204MB 98.08%                | github.com/qiangxue/fasthttp-routing.(*Router).HandleRequest
    19.                                             204MB   100% |   github.com/qiangxue/fasthttp-routing.(*Context).Next
    20. ----------------------------------------------------------+-------------
    21.                                             204MB   100% |   github.com/valyala/fasthttp.(*workerPool).workerFunc
    22.         0     0% 99.28%      204MB 98.08%                | github.com/valyala/fasthttp.(*Server).serveConn
    23.                                             204MB   100% |   main.startHttpServer.func8
    24. ----------------------------------------------------------+-------------
    25.         0     0% 99.28%      204MB 98.08%                | github.com/valyala/fasthttp.(*workerPool).getCh.func1
    26.                                             204MB   100% |   github.com/valyala/fasthttp.(*workerPool).workerFunc
    27. ----------------------------------------------------------+-------------
    28.                                             204MB   100% |   github.com/valyala/fasthttp.(*workerPool).getCh.func1
    29.         0     0% 99.28%      204MB 98.08%                | github.com/valyala/fasthttp.(*workerPool).workerFunc
    30.                                             204MB   100% |   github.com/valyala/fasthttp.(*Server).serveConn
    31. ----------------------------------------------------------+-------------
    32.                                             204MB   100% |   github.com/valyala/fasthttp.(*Server).serveConn
    33.         0     0% 99.28%      204MB 98.08%                | main.startHttpServer.func8
    34.                                             204MB   100% |   github.com/qiangxue/fasthttp-routing.(*Router).HandleRequest
    35. ----------------------------------------------------------+-------------
    36.         0     0% 99.28%        2MB  0.96%                | runtime.mstart
    37.                                               2MB   100% |   runtime.mstart0
    38. ----------------------------------------------------------+-------------
    39.                                               2MB   100% |   runtime.mstart
    40.         0     0% 99.28%        2MB  0.96%                | runtime.mstart0
    41.                                               2MB   100% |   runtime.mstart1
    42. ----------------------------------------------------------+-------------
    43.                                               2MB   100% |   runtime.mstart0
    44.         0     0% 99.28%        2MB  0.96%                | runtime.mstart1
    45.                                               2MB   100% |   runtime.schedule
    46. ----------------------------------------------------------+-------------
    47.                                            2.50MB   100% |   runtime.startm
    48.         0     0% 99.28%     2.50MB  1.20%                | runtime.newm
    49.                                            2.50MB   100% |   runtime.allocm
    50. ----------------------------------------------------------+-------------
    51.                                            2.50MB   100% |   runtime.schedule
    52.         0     0% 99.28%     2.50MB  1.20%                | runtime.resetspinning
    53.                                            2.50MB   100% |   runtime.wakep
    54. ----------------------------------------------------------+-------------
    55.                                               2MB 80.00% |   runtime.mstart1
    56.         0     0% 99.28%     2.50MB  1.20%                | runtime.schedule
    57.                                            2.50MB   100% |   runtime.resetspinning
    58. ----------------------------------------------------------+-------------
    59.                                            2.50MB   100% |   runtime.wakep
    60.         0     0% 99.28%     2.50MB  1.20%                | runtime.startm
    61.                                            2.50MB   100% |   runtime.newm
    62. ----------------------------------------------------------+-------------
    63.                                            2.50MB   100% |   runtime.resetspinning
    64.         0     0% 99.28%     2.50MB  1.20%                | runtime.wakep
    65.                                            2.50MB   100% |   runtime.startm
    66. ----------------------------------------------------------+-------------
     
    

    对比一下func3和func8

    1. (pprof) list func3
    2. Total: 208MB
    3. ROUTINE ======================== main.startHttpServer.func3 in E:\WORK\PROJECT\git\go\gohutool\boot4go-docker-ui\docker.ui.go
    4.     204MB      204MB (flat, cum) 98.08% of Total
    5.         .          .    180:
    6.         .          .    181:           if len(testPool) >= POOLSIZE {
    7.         .          .    182:                   testPool = testPool[0:0]
    8.         .          .    183:           }
    9.         .          .    184:
    10.     204MB      204MB    185:           testPool = append(testPool, make([]byte, SIZE))
    11.         .          .    186:
    12.         .          .    187:           return nil
    13.         .          .    188:   })
    14.         .          .    189:
    15.         .          .    190:   router.Any("/debug/pprof/*", func(ctx *routing.Context) error {

    1. (pprof) list func8
    2. Total: 208MB
    3. ROUTINE ======================== main.startHttpServer.func8 in E:\WORK\PROJECT\git\go\gohutool\boot4go-docker-ui\docker.ui.go
    4.         0      204MB (flat, cum) 98.08% of Total
    5.         .          .    248:
    6.         .          .    249:                   Logger.Debug("router.HandleRequest is finish")
    7.         .          .    250:
    8.         .          .    251:           }()
    9.         .          .    252:
    10.         .      204MB    253:           router.HandleRequest(ctx)
    11.         .          .    254:   }
    12.         .          .    255:
    13.         .          .    256:   //go http.ListenAndServe("0.0.0.0:8887", nil)
    14.         .          .    257:
    15.         .          .    258:   // Start HTTP server.

    heap提供了对内存进行分析的途径,通过对内存的占用量的分析,我们可以结合着程序的压力测试,对程序的内存泄漏进行排查和分析,对内存只增不减的等可疑情况地方,进行排查,最终发现问题

    heap的pprof样本中的数据项

    通过http://localhost:8999/debug/pprof/可以查看heap的信息

    技巧

    这些信息是样本中的数据项,相对于我们通过web访问时,访问当前时间的heap的一个快照; 熟悉这些数据项所表示的含义,也非常对我们了解当前程序运行时的内存情况非常有帮助。

    这里对应的样本的输出的源代码可以参考net/http/pprof/pprof.go, runtime/pprof/pprof.goruntime/mstats.go

  • 相关阅读:
    工作小记 编译 ffmpeg gpu 版本
    vue+ts做一个类似课程表
    linux安装Chrome跑web自动化
    有了低代码,二次开发都不是事!
    go 1.18新特性(泛性 模糊测试 WorkSpace)
    Anaconda的升级、配置及使用
    Windows使用小技巧
    Redis系列:Redis持久化机制与Redis事务
    Flutter iOS上架指南
    【Vue Router的路由模式】
  • 原文地址:https://blog.csdn.net/inthirties/article/details/125595978