首页 存档 技术 查看内容

单页面应用下的JS内存管理(2)--内存泄漏实战

2018-3-30 13:00 |来自: 互联网 283 0

摘要: 来源 /腾讯课堂Coding学院(ID:ke_coding)导读:在上一篇文章单页面应用下的JS内存管理(1)中,我主要介绍了容易引起致命内存泄漏的地方。本来想介绍下之前项目中排查内存泄漏的经验,但这样的话,就得使用之前错误 ...

来源 /腾讯课堂Coding学院(ID:ke_coding)

导读:在上一篇文章单页面应用下的JS内存管理(1)中,我主要介绍了容易引起致命内存泄漏的地方。本来想介绍下之前项目中排查内存泄漏的经验,但这样的话,就得使用之前错误的代码进行模拟,再一个就是之前的很多排查都是基于自己对项目本身的了解,写出来不一定很直观,读者也不能跟着进行实践操作,所以以上篇中的网易有数为例介绍如何进行排查。

阅读本文需要了解chrome dev tool的timelineprofile

在上篇中有一个非常好的例子网易有数,网易有数是一个非常优秀的数据可视化工具,可能是因为我提到的操作并不是普遍操作,对用户体验还没有太大影响,并没有引起开发测试的注意。本文将通过定位网易有数的内存泄漏来介绍如何排查内存泄漏,因为对项目架构不了解,再加上都是压缩后的代码,还是颇有难度的。

上文提到,很多内存泄漏发生在页面的局部刷新的时候,我怀疑其在页面刷新时会有内存泄漏

1
通过timeline查看整体内存结果

打开页面报表,点开timeline的录制按钮,点击刷新按钮,刷新页面数据。从下图timeline的分析数据可以看出,每次刷新后虽然有部分内存释放,但是总量却是稳步增加,并且nodes数也一样稳步增加。这时候就可以怀疑:有内存泄漏,且有部分DOM节点没能释放。

2
这可输入标题通过profile定为内存泄漏

通过timeline,我们怀疑发生了内存泄漏,下面我们就通过proflie去定为内存泄漏点。

重新刷新页面,用profile记录下初始内存快照,多次页面刷新后再次纪录下内存快照。chrome的profile提供了四种视图:

Summary 分类总览视图

Comparison 对比两次内存快照的结果视图

Containment 按照以GC root,全局对象的总览视图

Dominators 分类占比图(看看就好)

为什么要录下两次的内存快照呢?当然是比较两次内容,看看第二次到底多了哪些内容,我们自然选择Comparison视图,对比Snap 2与Snap 1,按照allocation size进行排序。(熟悉项目的也可以从detached DOM tree入手)

刚刚我刷新了10几次页面,因为是demo数据,十几次的数据都是一样的。也就是说应该会有很多组有10几个相同大小的内存块,上文提到这正是比较致命的内存泄漏(比如上图中大概10个12344大小的内存块)。我们便从这些入手进行分析:

看下这10个对象的Retainers视图, Retainers视图有四列

Object 显示该object到GC Root的详细路径

Distance 到GC Root的最短路径

Shallow Size 该对象直接占有的内存(因为js大多数都是引用,所以直接占有比较小)

Retained Size 一旦该对象被删除,能被释放的内存量

查看几组详细路径后,我一开始以为是chart引起的,但是chart的distance却高达11,而且这几组都有“_events.clickouter”这个相同的引用,会不会是事件委托造成的内存泄漏呢?hover到“clickouter”上(上图),我们可以定位到以下代码。说实话,我也被下面函数的引用关系给绕晕了。

注册一个clickouter处理,会在t变量push一个处理函数,同时返回一个处理后事函数,一旦用不到了,执行后处理后事。会不会是注册了clickouter,但是忘记了在周期结束后解绑呢?我们在这里打个断点看看,发现每次刷新,t的length都会增加12,我再打个断点在u()上,发现每次刷新都不会执行。看来我的怀疑是对的,为了验证我的想法,在执行过程中手动清空t变量(t=[])。我又重新录了一次内存快照,但是发现内存并没有下降,有可能是gc还没有执行,手动点击timeline的gc按钮,建议gc执行。2分钟后再次录制,内存已经从150M降到44M,接近于初始状态。泄漏点成功定位!

业界最顶尖的技术大咖/最权威的实战分享/最前沿的行业资讯/尽在腾讯课堂Coding学院

长按二维码关注Coding学院

声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

相关分类

返回顶部