1

Golang分析内存溢出

 2 years ago
source link: https://zacharyfan.com/archives/1569.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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/ 看到相关的性能维度

a1569_1.png

上图中框出的这 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」入口,我们可以看到实时内存的使用情况。

a1569_2.png

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

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

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

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

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

list main.main

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

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

a1569_5.png

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

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

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

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

a1569_6.png

如果是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 文件在程序运行的目录下。

a1569_7.png

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

同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)。坚持用心打磨每一篇高质量原创。欢迎扫描二维码~

微信公众号

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

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

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


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK