Golang处理内存溢出方式

 更新时间:2024年12月20日 10:08:33   作者:dkjhl  
本文介绍了Golang中分析内存溢出问题的三种工具:pprof、GoMemstats和程序crash时自动创建dump文件,通过这些工具,可以对程序的内存使用情况进行详细分析,从而找出内存溢出的原因

背景

最近系统在压测过程中发现主程序在并发增大后会出现主程序闪退现象,几经波折,认为有可能是内存溢出引起的

正好对 Golang 里分析 dump 这块还没怎么涉及,借此契机研究一下。

前言

查看社区后,发现在Golang中,发生内存溢出通常会导致程序直接崩溃退出,而无法像其他语言一样生成core dump文件。

因此,Golang社区提供了一些工具可以帮助用户进行内存分析。

以下是两个常用的工具:

1. pprof

pprof是Golang内置的性能分析工具,在分析内存使用方面非常有用。

通过设置一个标志位并在程序退出时打开pprof服务器,程序可以向pprof服务器报告一些性能数据,例如内存使用情况。

可以在代码中加入以下代码,启动pprof服务器并在本地8080端口进行访问:

import "net/http"
import _ "net/http/pprof"

func main() {
    go func() {
        http.ListenAndServe("localhost:8080", nil)
    }()
    // ...
}

启动pprof服务器之后,可以访问http://localhost:8080/debug/pprof/heap进行堆内存分析,获取内存占用的堆快照。

上图中框出的这 4 个部分应该是平时最常用的,从上往下分别是:

  • 阻塞分析: 比如,goroutine 的 wait。
  • 内存分析: 比如,内存泄漏、内存消耗异常等情况。
  • 互斥锁分析: 比如,观察代码里用到的sync.RWMutex 和 sync.Mutex 的具体情况。
  • CPU 分析: 比如,排查哪些代码较多地占用了 CPU 资源。

以下是一段消耗内存的代码,用于走读流程,如下:

func main() {
	go func() { http.ListenAndServe("0.0.0.0:8899", nil) }()
	str := "gejigejigejigejigejigejigejigjeijgiewjiasdiahdkuhakudsfhakdshgkjasdkjgbakjsdfioajewoiepqbibgijqbgoipbjwebkjfqjkw egqhwejbgfaijwebgjqhb"
	for i := 0; i < 999; i++ {
		str += str
	}
	fmt.Scanln()
}

在 web 页面点击「heap」入口,我们可以看到实时内存的使用情况。

再通过以下命令进入到命令交互模式看看效果:

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

进去之后输入「top」,就能很直观的看到哪个方法占用了内存。

这里的几个列的含义简单罗列下:

  • flat:当前函数所占用的容量。
  • flat%:当前函数所占用的容量,在总分配容量的百分比。
  • sum%:是从调用的最外层到当前方法累加使用的容量占总容量的百分比
  • cum:当前函数以及子函数所占用的容量。
  • cum%:当前函数以及子函数所占用的容量,在总分配容量的百分比。
  • 最后一列是函数的名字

可以再输入获得更详细的信息:

list main.main

上述指令会罗列出每行代码占用的容量;其他类似,如下是分析CPU的

2. Go Memstats

Go Memstats是一个Golang的标准库工具,用于收集和显示内存信息。

可以在代码中导入“runtime”包,并调用“runtime.ReadMemStats(&mem)”函数收集内存信息。

然后可以打印内存使用情况的详情,例如总分配量和分配的堆块数量等。

以下是示例代码:

import (
    "fmt"
    "runtime"
)

func main() {
    var mem runtime.MemStats
    runtime.ReadMemStats(&mem)
    fmt.Printf("TotalAlloc (Heap) = %v MiB\n", mem.TotalAlloc/mb)
    fmt.Printf("Alloc = %v MiB\n", mem.Alloc/mb)
    fmt.Printf("Sys = %v MiB\n", mem.Sys/mb)
    fmt.Printf("NumGC = %v\n", mem.NumGC)
}

这将输出程序中已分配的总内存,已使用的内存量,系统内存使用情况和垃圾回收次数等信息。

使用这些信息,可以分析内存占用量的增长和优化内存使用。

3. 程序 crash 的时候自动创建 dump 文件

大多数时候,我们可能没有条件实时分析程序运行情况。

比如问题在生产环境偶发出现,且无法在测试环境重现。

这个时候我们可以配置当程序 crash 的时候自动保存 dump 文件。

先输入命令「ulimit -a」看下当前是否开启了core file。

这里的数字单位是 block,具体需要根据所在的操作系统一个 block 对应的大小来设置。如果是0的话说明未开启。可以通过:

ulimit -c 1024 或者 ulimit -c unlimited 来设置 dump 文件的最大 size。

如果想要永久有效,则:

echo "ulimit -c unlimited" >> ~/.profile

让程序发生 crash 的时候会自动生成 dump 文件

## 临时有效
export GOBACTRACE=crash

## 永久有效
echo "export GOTRACEBACK=crash " >> ~/.profile

这就意味着,让程序发生 crash 的时候会自动生成 dump 文件。

有了 dump 文件,可以用 gdb 或者 delve 工具来分析了(官方更建议我们使用 delve,对 Golang 的支持更好)

总之啊,无论你使用哪种工具,分析Golang内存溢出问题需要耐心和技巧。

建议不仅可以使用这些工具进行数据分析,同时还应该阅读关于垃圾回收机制和内存管理的文档,尝试实现更好的编码习惯,以减少内存溢出的可能性。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • go语言中gorm时间格式化

    go语言中gorm时间格式化

    本文主要介绍了go语言中gorm时间格式化,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-03-03
  • Go调用C++动态库实现车牌识别的示例代码

    Go调用C++动态库实现车牌识别的示例代码

    本文主要介绍了如何利用C++中Opencv、TensorRT等库编译出动态库供Go调用,再写个简单的api对上传的车辆图片进行车牌识别,文中通过代码示例给大家介绍的非常详细,需要的朋友可以参考下
    2023-12-12
  • 关于升级go1.18的goland问题详解

    关于升级go1.18的goland问题详解

    作为一个go语言程序员,觉得自己有义务为go新手开一条更简单便捷的上手之路,下面这篇文章主要给大家介绍了关于升级go1.18的goland问题的相关资料,需要的朋友可以参考下
    2022-11-11
  • Go设计模式之原型模式图文详解

    Go设计模式之原型模式图文详解

    原型模式是一种创建型设计模式, 使你能够复制已有对象, 而又无需使代码依赖它们所属的类,本文将通过图片和文字让大家可以详细的了解Go的原型模式,感兴趣的通过跟着小编一起来看看吧
    2023-07-07
  • Go实现mongodb增删改查工具类的代码示例

    Go实现mongodb增删改查工具类的代码示例

    这篇文章主要给大家介绍了关于Go实现mongodb增删改查工具类的相关资料,MongoDB是一个NoSQL数据库,它提供了灵活的文档存储模型以及强大的查询和操作功能,需要的朋友可以参考下
    2023-10-10
  • 深入了解Golang包的获取方法

    深入了解Golang包的获取方法

    Go语言有一个获取远程包的工具就是go get,本文将详细为大家介绍一下Go语言包的获取的方法,文中的示例代码讲解详细,感兴趣的可以了解一下
    2022-07-07
  • Windows下在CMD下执行Go出现中文乱码的解决方法

    Windows下在CMD下执行Go出现中文乱码的解决方法

    在cmd下运行go程序或者是GOLAND的Terminal下运行go程序会出现中文乱码的情况。本文就详细的介绍下解决方法,具有一定的参考价值,感兴趣的可以了解一下
    2021-12-12
  • Golang实现EasyCache缓存库实例探究

    Golang实现EasyCache缓存库实例探究

    这篇文章主要为大家介绍了Golang实现EasyCache缓存库实例探究,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • go语言-在mac下brew升级golang

    go语言-在mac下brew升级golang

    这篇文章主要介绍了go语言-在mac下brew升级golang,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • 解决Golang map range遍历结果不稳定问题

    解决Golang map range遍历结果不稳定问题

    这篇文章主要介绍了解决Golang map range遍历结果不稳定问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12

最新评论