首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Golang和HeapAlloc与pprof大差的比较

Golang和HeapAlloc与pprof大差的比较
EN

Stack Overflow用户
提问于 2019-05-15 13:30:21
回答 2查看 2.2K关注 0票数 6

我有一个计算内存中大型相关矩阵的Go程序。为此,我已经设置了一个3 goroutines的管道,其中第一个读取文件,第二个计算相关矩阵,最后一个将结果存储到磁盘。

问题是,当我运行程序时,Go运行时分配~17 3GB内存,而矩阵只占用~2-3GB。使用runtime.ReadMemStats显示程序使用~17 by (并通过htop验证),但pprof只报告了~2.3GB。

如果在管道中运行一个文件后查看mem统计数据:

代码语言:javascript
复制
var mem runtime.MemStats
runtime.ReadMemStats(&mem)
fmt.Printf("Total alloc: %d GB\n", mem.Alloc/1000/1000/1000)

这显示了方案的总分配情况:

代码语言:javascript
复制
Total alloc: 17 GB

但是,如果运行go tool pprof mem.prof,则会得到以下结果:

代码语言:javascript
复制
(pprof) top5
Showing nodes accounting for 2.21GB, 100% of 2.21GB total
Showing top 5 nodes out of 9
      flat  flat%   sum%        cum   cum%
    1.20GB 54.07% 54.07%     1.20GB 54.07%  dataset.(*Dataset).CalcCorrelationMatrix
    1.02GB 45.93%   100%     1.02GB 45.93%  bytes.makeSlice
         0     0%   100%     1.02GB 45.93%  bytes.(*Buffer).WriteByte
         0     0%   100%     1.02GB 45.93%  bytes.(*Buffer).grow
         0     0%   100%     1.02GB 45.93%  encoding/json.Indent

因此,我想知道如何才能了解为什么程序分配17 GB,而似乎峰值内存使用量只有~2.5GB?有没有一种方法可以在整个程序中使用pprof跟踪内存的使用情况?

编辑

我再次使用GODEBUG=gctrace=1运行该程序,并得到以下跟踪:

代码语言:javascript
复制
gc 1 @0.017s 0%: 0.005+0.55+0.003 ms clock, 0.022+0/0.47/0.11+0.012 ms cpu, 1227->1227->1226 MB, 1228 MB goal, 4 P
gc 2 @14.849s 0%: 0.003+1.7+0.004 ms clock, 0.015+0/1.6/0.11+0.018 ms cpu, 1227->1227->1227 MB, 2452 MB goal, 4 P
gc 3 @16.850s 0%: 0.006+60+0.003 ms clock, 0.027+0/0.46/59+0.015 ms cpu, 1876->1876->1712 MB, 2455 MB goal, 4 P
gc 4 @22.861s 0%: 0.005+238+0.003 ms clock, 0.021+0/0.46/237+0.015 ms cpu, 3657->3657->3171 MB, 3658 MB goal, 4 P
gc 5 @30.716s 0%: 0.005+476+0.004 ms clock, 0.022+0/0.44/476+0.017 ms cpu, 5764->5764->5116 MB, 6342 MB goal, 4 P
gc 6 @46.023s 0%: 0.005+949+0.004 ms clock, 0.020+0/0.47/949+0.017 ms cpu, 10302->10302->9005 MB, 10303 MB goal, 4 P
gc 7 @64.878s 0%: 0.006+382+0.004 ms clock, 0.024+0/0.46/382+0.019 ms cpu, 16548->16548->7728 MB, 18011 MB goal, 4 P
gc 8 @89.774s 0%: 0.86+2805+0.006 ms clock, 3.4+0/24/2784+0.025 ms cpu, 20208->20208->17088 MB, 20209 MB goal, 4 P

因此,很明显,堆在程序中稳步增长,但我无法确定具体的位置。在调用内存密集型函数之后,我使用pprof.WriteHeapProfile分析了内存的使用情况:

代码语言:javascript
复制
func memoryProfile(profpath string) {

    if _, err := os.Stat(profpath); os.IsNotExist(err) {
        os.Mkdir(profpath, os.ModePerm)
    }

    f, err := os.Create(path.Join(profpath, "mem.mprof"))
    fmt.Printf("Creating memory profile in %s", "data/profile/mem.mprof\n")
    if err != nil {
        panic(err)
    }

    if err := pprof.WriteHeapProfile(f); err != nil {
        panic(err)
    }
    f.Close()
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-01-15 11:51:34

正如JimB在注释中提到的,go配置文件是一个采样分析器,并在一定的时间间隔内采样内存使用情况。在我的例子中,采样不够频繁,无法捕获使用大量内存的函数(JSON编组)。

通过设置环境变量来提高分析器的采样率

$ export GODEBUG=memprofilerate=1

将更新runtime.MemProfileRate,而配置文件现在包括每个分配的块。

票数 3
EN

Stack Overflow用户

发布于 2020-11-02 21:44:40

一个可能的解决方案(就像在我的例子中那样)是使用-race编译的二进制文件,它允许检查争用条件。

这方面的开销很大,如果使用htop或其他类似的方法检查,它看起来就像一个巨大的内存泄漏,但不会显示在任何pprof输出中。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56150617

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档