关于go:Go-内存泄漏pprof-够用了吗

40次阅读

共计 2658 个字符,预计需要花费 7 分钟才能阅读完成。

文|朱德江(GitHub ID:doujiang24)

MOSN 我的项目外围开发者、蚂蚁团体技术专家

专一于云原生网关研发的相干工作

本文 2651 字 浏览 8 分钟

MOSN 是次要应用 Go 语言开发的云原生网络代理平台,在蚂蚁团体有着几十万容器的大规模生产利用。在这种大规模的利用中,常常会遇到各种内存问题,通常状况下 pprof heap profile 能够很好帮忙剖析问题。不过,有时候 pprof 也不够用,也就须要咱们有更适合的工具了。

Part.1– 出生证 vs 暂住证

首先 pprof 的确很好用,设计实现也都很精美,有趣味的能够查看这篇《Go 语言 pprof heap profile 实现机制》[1]。

用 pprof 来剖析内存透露,通常状况下是够用了,不过有时候,也会不够用。

这是为什么呢?因为 pprof 只是记录了内存对象被创立时的调用栈,并没有援用关系 。也就是说,没有方法晓得,内存对象是因为被谁援用了而导致没有被开释。对此,我的共事 – 烈元同学有一个很形象的比喻,pprof 只能看到出生证,却查不了暂住证。

Part.2– 须要援用关系

有些场景下,咱们晓得了透露的内存是从哪里申请的,然而翻了半天代码,也搞不清楚内存为什么没有开释。比方,内存对象通过简单的调用传递,或者简单的内存池复用机制,又或者传给了某个不相熟的第三方库,在第三方库中有非预期的应用……

在这些状况下,咱们会有一个很直觉的想法是,想看看这些内存对象的援用关系。

Part.3– 内存援用关系火焰图

内存援用关系火焰图,是一种内存对象援用关系的可视化形式,最早利用于 OpenResty XRay 产品。这个工具的确是内存剖析神器,给不少的客户定位过内存问题,感兴趣的能够移步 OpenResty 官网博客 [2]。

下图是由一个 MOSN 服务产生的,自下而上示意的是从 GC root 到 GC object 的援用关系链,宽度示意的是对象大小 (也包含其援用的对象的大小之和)

有了这样的可视化后果,咱们就能够直观的看到内存对象的援用关系。

比方下图最宽的局部,示意的是 MOSN 中 cluster_manager 全局变量中援用的 cluster 内存对象:

https://github.com/mosn/mosn/blob/aecc93c4b2b4801e7992387f245fe9eefa45733d/pkg/upstream/cluster/cluster_manager.go#L82

Part.4– 实现原理

在生成火焰图之前,首先咱们须要提取两个要害信息:

每个内存对象之间的援用关系;

每个内存对象的类型。

援用关系

获取援用关系比较简单,首先,咱们能够在 heap 中找到所有的 GC 对象。而后遍历所有的对象,再联合 bitmap 信息,获取这个对象援用的其余对象。基本原理跟 GC mark 是相似的,尽管实现上很不一样,但因为这个是离线工具,能够简略粗犷的实现。

类型推导

Go 语言作为编译型动态语言,是不须要为每个内存对象存储类型信息的 (有点例外的是 interface)。如果是动静类型语言,比方 Lua,则会不便很多,每个 GC 对象都存储了对象的类型。

所以,要获取每个对象的类型,还是比拟麻烦的,也是投入工夫最多的一块。当然,还是有解决办法的,简略来说就是做逆向类型推导,依据已知内存的类型信息,推导被援用的内存对象的类型信息。

这块还是比较复杂的,有趣味的能够看这篇《Go 语言,如何做逆向类型推导》[3] 的介绍。

生成过程

有了这两个要害信息之后,生成过程如下还是比拟清晰的:

1. 获取所有的内存对象,包含类型、大小,以及他们之间的援用关系,造成一个图;

2. 从 root 对象登程,依照档次遍历,造成一棵树 (也就是剪枝过程,每个对象只能被援用一次)

3. 将这棵树的残缺援用关系,当做 backtrace dump 下来,count 是以后节点的总大小 (包含所有子节点),也就是火焰图上的宽度;

4. 从 bt 文件生成 svg,这一步是 brendangregg 的 FlameGraph 规范工具链。

Part.5– 应用形式

这个工具是基于 Go 官网的 viewcore 改良来的。不过,鉴于 Go 官网不那么热心保护 viewcore 了,MOSN 社区先 fork 了一份,搞了个 mosn 分支,作为 MOSN 社区保护的主分支。

之前也给 Go 官网 debug 提交了好几个 bugfix,等前面有空,咱们再去提交这个 feature。

所以,应用形式如下:

# 编译 mosn 保护的 viewcore
git clone git@github.com:mosn/debug.git
cd debug/cmd/viewcore
go build .

# 假如曾经有了一个 core 文件(CORE-FILE)# 以及对应的可执行程序文件(BIN-FILE)viewcore CORE-FILE --exe BIN-FILE objref ref.bt

# 下载 FlameGraph 工具
git clone git@github.com:brendangregg/FlameGraph.git
../FlameGraph/stackcollapse-stap.pl ref.bt | ../FlameGraph/flamegraph.pl> ref.svg

# 浏览器关上 ref.svg 即可看到火焰图 

如果应用碰到问题,能够随时分割咱们或提交 issue(https://github.com/mosn/mosn/issues)。

当然,假使你胜利定位了某个问题,也欢送与咱们独特分享,Let’s have fun together!

MOSN 用户钉钉群:33547952

相干链接

[1]《Go 语言 pprof heap profile 实现机制》:https://uncledou.site/2022/go-pprof-heap/

[2]OpenResty 官网博客:https://blog.openresty.com.cn/cn/openresty-xray-case-yundun/

[3]《Go 语言,如何做逆向类型推导》:https://uncledou.site/2022/go-type-derivation/

理解更多…

MOSN Star 一下✨: https://github.com/mosn/mosn

插播一条好消息!🤩

对 Go 语言开发感兴趣的小伙伴们, 欢送大家参加到近期正热的 GoCity 我的项目体验

点击此处查看演示视频,疾速入门吧🥳

本周举荐浏览

MOSN 反向通道详解

Go 原生插件应用问题全解析

Go 代码城市上云 –KusionStack 实际

MOSN 文档使用指南

欢送扫码关注:

正文完
 0