Golang分析内存溢出

我是一个着迷于产品和运营的技术人,乐于跨界的终身学习者。欢迎关注我的个人公众号「跨界架构师」

每周五11:45 按时送达

我的第「223」篇原创敬上

 

大家好,我是Z哥。

最近系统在压测过程中发现有一个程序在压力增大后会内存溢出。正好之前自己对 Golang 里分析 dump 这块还没怎么涉及,借此契机学习一下。

网上搜了很多资料,发现 Golang 好像没有手动创建 dump 文件的方式(像 Java 的 jmap,.Net 的创建转储文件这种)。

要么通过设置环境变量,在程序 crash 的时候自动创建 dump 文件,要么程序里 import 一个 pprof 的 package,实时分析 dump 相关的信息。

如果有哪位老司机知道手动创建 dump 的方式,请在评论区教下大家,感谢~

下面我手把手教大家如何通过以上两种方式来分析内存溢出问题,步骤详细,包教包会,建议收藏~

 

/01  通过 pprof 实时分析/

pprof 全称是 performance profiles,是 google 官方提供的性能分析工具,项目地址:https://github.com/google/pprof。配合 Graphviz 使用可以提供图形化的能力。

使用它的方式很简单,配合 pprof 库来使用。只要在代码里增加两块代码。一块是 import:

_”net/http/pprof”

另一块是main函数的开头部分

go func() {

http.ListenAndServe(“0.0.0.0:8899”,nil)//ip和端口可以更换

}()

然后就可以在浏览器里输入 http://localhost:8899/debug/pprof/ 看到相关的性能维度

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

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

虽然直接在浏览器页面上也能看到一些信息,但是用来分析是不够的,想要真正能分析问题还得通过前面提到的 pprof 工具。

使用 go tool pprof 分析数据,有两种方式:

  • 通过url。go tool pprof  http://localhost:8899/debug/pprof/profile
  • 通过文件。go tool pprof cpuprofile  文件路径

 

好了,我们来试一下。

Z哥写了一段消耗内存的代码,如下:

func main() {

go func() {

http.ListenAndServe(“0.0.0.0:8899”, nil)

}()

str := “sadasdasffrgrgrgrgrgrfefafasfsadasdasffrgrgrgrgrgrfefafasfsadasdasffrgrgrgrgrgrfefafasfsadasdasffrgrgrgrgrgrfefafasfsadasdasffrgrgrgrgrgrfefafasfsadasdasffrgrgrgrgrgrfefafasf”

for i := 0; i < 999; i++ {

str += str

}

fmt.Scanln()

}

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

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

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

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

这里的几个列的含义简单罗列下:
  1. flat:当前函数所占用的容量。
  2. flat%:当前函数所占用的容量,在总分配容量的百分比。
  3. sum%:是从调用的最外层到当前方法累加使用的容量占总容量的百分比
  4. cum:当前函数以及子函数所占用的容量。
  5. cum%:当前函数以及子函数所占用的容量,在总分配容量的百分比。
  6. 最后一列是函数的名字

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

list main.main

每一行代码占用了多少容量直接给你罗列出来了,是不是很香。

分析其他的也是类似的,比如以下是分析 CPU 的。

/02 程序 crash 的时候自动创建 dump 文件/

大多数时候,我们可能没有条件实时分析程序运行情况。比如问题在生产环境偶发出现,且无法在测试环境重现。

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

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

如果是0的话说明未开启。可以通过:

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

这里的数字单位是 block,具体需要根据所在的操作系统一个 block 对应的大小来设置。

如果你想让这个设置永久生效那么需要将它添加到 /.profile 中

echo “ulimit -c unlimited” >> ~/.profile

再看下 Golang 的环境变量 GOTRACEBACK 的设置是什么,

export

如果不是 crash 或者不存在 GOTRACEBACK 的环境变量(默认是 none)的话,改成 crash。

export GOBACTRACE=crash

这就意味着,让程序发生 crash 的时候会自动生成 dump 文件。(Z哥在 mac 系统上运行没能自动生成 dump 文件,但在 centos 上可以)

然后运行的程序如果发生 panic,会自动生成 dump 文件在程序运行的目录下。

红框圈出来的是它的默认文件名的格式。

同unlimited 一样,也需要让这个设置永久生效的话,需要添加到/.profile中

echo “export GOTRACEBACK=crash ” >> ~/.profile

有了 dump 文件,你就可以用 gdb 或者 delve 工具来分析了(官方更建议我们使用 delve,对 Golang 的支持更好),这里就先不展开了。

一般来说,建议大家如果在本地环境的话使用 pprof 就好了,如果在服务器上,务必开始 crash 自动保存 dump 的功能,便于后续的快速定位问题并分析。

 

好了,这篇呢,Z 哥和你分享了在 Golang 中分析运行时的代码问题。主要有两种途径:

  • 通过 pprof 实时分析。
  • 程序 crash 时自动保存 dump,再通过 delve 或者 gdb 分析。

希望对你有所帮助。建议收藏,以防不备之需~

 



原创文章,转载请注明本文链接: https://zacharyfan.com/archives/1569.html

关于作者:张帆(Zachary,个人微信号:Zachary-ZF)。坚持用心打磨每一篇高质量原创。欢迎扫描二维码~

微信公众号

定期发表原创内容:架构设计丨分布式系统丨产品丨运营丨一些思考。

如果你是初级程序员,想提升但不知道如何下手。又或者做程序员多年,陷入了一些瓶颈想拓宽一下视野。欢迎关注我的公众号「跨界架构师」,回复「技术」,送你一份我长期收集和整理的思维导图。

如果你是运营,面对不断变化的市场束手无策。又或者想了解主流的运营策略,以丰富自己的“仓库”。欢迎关注我的公众号「跨界架构师」,回复「运营」,送你一份我长期收集和整理的思维导图。

Leave a Reply

发表评论

电子邮件地址不会被公开。 必填项已用*标注

ZacharyFan.com © 2019 | WordPress Theme: BlogGem by TwoPoints.