如何分析golang内存?

 王尼玛的脑残粉 发布于 2023-01-01 20:41

我写了一个golang程序,它在运行时使用1.2GB的内存.

调用go tool pprof http://10.10.58.118:8601/debug/pprof/heap只有323.4MB堆使用量的转储结果.

剩下的内存使用情况如何?

有没有更好的工具来解释golang运行时内存?


使用gcvis我得到这个:

在此输入图像描述

..和这个堆形式配置文件:

在此输入图像描述

这是我的代码:https://github.com/sharewind/push-server/blob/v3/broker

4 个回答
  • 堆配置文件显示活动内存,运行时认为正由go程序使用的内存(即:垃圾收集器尚未收集).当GC收集内存时,配置文件会缩小,但系统不会返回任何内存.在向系统询问更多信息之前,您将来的分配将尝试使用先前收集的对象池中的内存.

    从外部来看,这意味着您的程序的内存使用量将会增加或保持水平.外部系统作为程序的"驻留大小"呈现的是RAM分配给程序的字节数,无论它是否保留使用中的值或收集的值.

    这两个数字通常完全不同的原因是:

      GC采集存储器对程序的外部视图没有影响

      内存碎片

      只有在使用的内存在前一个GC之后使用的内存加倍时,GC才会运行(默认情况下,请参阅:http://golang.org/pkg/runtime/#pkg-overview)

    如果您想要准确分解Go如何看待内存,可以使用runtime.ReadMemStats调用:http://golang.org/pkg/runtime/#ReadMemStats

    或者,如果您可以通过以下方式通过浏览器访问分析数据,那么您正在使用基于Web的分析:http://10.10.58.118:8601/debug/pprof/单击堆链接将显示堆配置文件的调试视图,该视图的打印输出为runtime.MemStats结构.底部.

    runtime.MemStats文档(http://golang.org/pkg/runtime/#MemStats)有所有字段的解释,但讨论的有趣内容是:

    HeapAlloc:本质上是探查器给你的东西(活动堆内存)

    Alloc:类似于HeapAlloc,但对于所有人来说都是管理内存

    Sys:从OS请求的内存总量(地址空间)

    系统管理系统报告之间仍然存在差异,因为操作系统报告的内容以及系统提供的内容并不总是相同的.go也没有跟踪CGO/syscall(例如:malloc/mmap)内存.

    2023-01-01 20:44 回答
  • 我总是对Go应用程序不断增长的住宅内存感到困惑,最后我不得不学习Go生态系统中存在的分析工具.运行时在runtime.Memstats结构中提供了许多指标,但可能很难理解它们中的哪一个可以帮助找出内存增长的原因,因此需要一些额外的工具.

    分析环境

    在您的应用程序中使用https://github.com/tevjef/go-runtime-metrics.例如,你可以把它放在你的main:

    import(
        metrics "github.com/tevjef/go-runtime-metrics"
    )
    func main() {
        //...
        metrics.DefaultConfig.CollectionInterval = time.Second
        if err := metrics.RunCollector(metrics.DefaultConfig); err != nil {
            // handle error
        }
    }
    

    运行InfluxDBGrafana内部Docker容器:

    docker run --name influxdb -d -p 8086:8086 influxdb
    docker run -d -p 9090:3000/tcp --link influxdb --name=grafana grafana/grafana:4.1.0
    

    设置Grafana和之间的交互InfluxDB Grafana(Grafana主页 - >左上角 - >数据源 - >添加新数据源):

    在此输入图像描述

    从https://grafana.com导入仪表板#3242(Grafana主页 - >左上角 - >仪表板 - >导入):

    在此输入图像描述

    最后,启动您的应用程序:它会将运行时指标传输给有争议的应用程序Influxdb.将您的应用程序置于合理的负载下(在我的情况下,它非常小 - 几个小时的5 RPS).

    内存消耗分析

      Sys(synonim of RSS)曲线与HeapSys曲线非常相似.事实证明,动态内存分配是整体内存增长的主要因素,因此堆栈变量消耗的少量内存似乎是不变的,可以忽略不计;

      恒定量的goroutines保证没有goroutine泄漏/堆栈变量泄漏;

      在过程的生命周期中,分配的对象总量保持不变(考虑到波动没有意义).

      最令人惊讶的事实是:HeapIdle以与a相同的速度增长Sys,而HeapReleased始终为零.显然,运行时不返回内存OS 所有,至少在这个试验的条件下:

    HeapIdle minus HeapReleased estimates the amount of memory    
    that could be returned to the OS, but is being retained by
    the runtime so it can grow the heap without requesting more
    memory from the OS.
    

    在此输入图像描述在此输入图像描述

    对于那些试图调查内存消耗问题的人,我建议按照所描述的步骤排除一些微不足道的错误(比如goroutine leak).

    明确释放内存

    有趣的是,通过显式调用,可以显着减少内存消耗debug.FreeOSMemory():

    // in the top-level package
    func init() {
       go func() {
           t := time.Tick(time.Second)
           for {
               <-t
               debug.FreeOSMemory()
           }
       }()
    }
    

    对照

    实际上,与默认条件相比,这种方法节省了大约35%的内存.

    2023-01-01 20:46 回答
  • 作为@Cookie of Nine的答案的补充,简而言之:你可以试试这个--alloc_space选项.

    go tool pprof--inuse_space默认使用.它会对内存使用情况进行抽样,因此结果是真实的一部分.
    通过--alloc_spacepprof返回自程序启动以来所有分配的内存.

    2023-01-01 20:46 回答
  • 您还可以使用StackImpact,它自动记录常规的和异常触发的内存分配配置文件并将其报告给仪表板,这些配置文件以历史记录和可比较的形式提供。有关更多详细信息,请参见此博客文章。Production Go应用程序中的内存泄漏检测

    免责声明:我为StackImpact工作

    2023-01-01 20:46 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有