![90d0bbb34a44bb4c1658b59f4755bc8f.png](https://i-blog.csdnimg.cn/blog_migrate/8603293c0cc21517daaff20fb2607b59.jpeg)
发现这个React 内存泄露问题是某一天的晚上一直开着直播页,直播页用的 react 版本是 16.8.6,到了早上跳到这个页面的时候,控制台有点卡,怀疑是有内存泄露,于是就开始分析这个直播页面。
分析
打开控制台 performance
面板点击开始录制,如下:
![c00061874c177ca4853255faa339050e.png](https://i-blog.csdnimg.cn/blog_migrate/ee951de151eb1dff92e7605003993513.png)
从上图可以发现在这时间内, nodes 节点一直在增长,很有可能发生了内存泄露。
我们来到 memory
面板分析内存变化:
![4aa8c26b6a3af4b8c9b0ff1c7ed41e58.png](https://i-blog.csdnimg.cn/blog_migrate/648bc9c4fadedec384507eb36e7f7408.jpeg)
注:上图的蓝色线条表示在时间轴的最后该对象依旧存在,灰色线条则说明对象在时间轴内被分配,但是已经被gc(垃圾回收)了。
上图都是点击 gc 再进行记录的,但是上图还有很多蓝色线条,而且内存一直往上涨,很明显的内存泄露问题,那会是什么导致内存泄露的呢?
很快发现这里有个 bi 的东西居然占了 31%的大小:
![a5cbe02172eabe6bba7d53d5bca66a61.png](https://i-blog.csdnimg.cn/blog_migrate/7a5c0743ed25b43d57282549cc69754b.jpeg)
这个 bi 是用来干嘛的?展开 bi ,鼠标悬浮在 bi 某处:
![57333a4e3d3b4aae6390c471bc4eaf59.png](https://i-blog.csdnimg.cn/blog_migrate/e4c85e4a35e6bbc08241428fe5316c4d.jpeg)
发现这个节点是直播间里的进房消息,里面是 react 存的 FiberNode
节点,观察了一下里面这些 bi 基本上都是消息元素。
选择 summary
,选出Detached
(分离)的元素:
![45101fdd1a5a41965fd0e06ad52e69b6.png](https://i-blog.csdnimg.cn/blog_migrate/8d74210709addf6bbde487f0dc0cc046.jpeg)
Detached HTMLDivElement
居然有41429个,展开,鼠标悬浮:
![02a4eadf3a55077f663a930d57809bbf.png](https://i-blog.csdnimg.cn/blog_migrate/eae83e26fcb67e66458a0349329cdd8c.jpeg)
还是消息信息,说明是这个导致 bi 增加的。我们继续展开:
![19baac53bf957bc2156903a7be93dad4.png](https://i-blog.csdnimg.cn/blog_migrate/ceca2057596fa2ac2779b4b2b284d80d.jpeg)
从上图看 react 会保留消息的上下兄弟节点的引用,而且保留的引用层级有点深,各个节点嵌套依赖,导致一直存在内存里:
![8f166a029b3ced5c7fef74ac6efb21af.png](https://i-blog.csdnimg.cn/blog_migrate/ce6de1a31cfb8168bec92d2de8d2c8fb.jpeg)
仔细查下了项目消息相关代码,发现并不会存在有内存泄露的操作。这里简单说下渲染消息的逻辑,消息有进房消息,聊天消息,礼物消息等等,消息展示会根据 messages 数组里面的类型去渲染不同的消息。messages 数组不会无限增长,控制在 100 个,超过就删掉第一个元素,保证维持100个元素渲染消息,但是从上图来看,这些分离的元素并没有被 react 完全删除,还保存在内存里,查了下 React 的 Issue,并查了相关文章,发现有不少人遇到这个问题:
- https://github.com/facebook/react/issues/16138
- https://github.com/facebook/react/issues/14732
- https://github.com/facebook/react/issues/18116
- Investigating Discord’s React Memory Leak - Discord Blog
React 核心成员 Dan 给出的解决办法是升级到 16.9.0。
这里将项目 React 和 React-dom 版本升级16.9.0, 发现 FiberNode 节点还是会一直增加。。。
![cabfb10027a24b7c17311780a0fe2be7.png](https://i-blog.csdnimg.cn/blog_migrate/c3cd0d305fff6cc3f5a911c24efdbd91.jpeg)
![959eedce90526a243e057481580c36fa.png](https://i-blog.csdnimg.cn/blog_migrate/fbc316f2cf2df50b1d5d5ca3988ae23a.png)
继续查看Issue 发现,React 版本 0.0.0-241c4467e
修复了这个问题。 Bug: Detached DOM node memory leak · Issue #18066 · facebook/react · GitHub
这个版本的 mr 已经合并在 React master 上 Null stateNode after unmount by bvaughn · Pull Request #17666 · facebook/react · GitHub
这个 mr 是 2019 年 12 月 20 号合并的,2019 年 12 月 20 号之后的版本是 16.13.0,这里将项目直接升级到 16.13.1,然后查看 node 节点:
![f8a82617c43747ceffafdc2d3a9bd441.png](https://i-blog.csdnimg.cn/blog_migrate/e03db010be9fe3cce82646fe2a37abd4.jpeg)
发现 node 节点可以降下来了,查看 memory
面板:
![15c16d49a1ffcb03b8414deafc4294bd.png](https://i-blog.csdnimg.cn/blog_migrate/21c10fb095007776844bb7dce3007a3a.jpeg)
对比Snapshot 5
,分离的元素没有新增,说明这个版本基本修复了这个问题。
结论
React 16.8.6 (16.2.5到16.12.0 可能会有,这些版本没有验证,但是 issue 里面有人遇到)的版本会存在内存泄露问题,建议升级 React 到 16.13.0 以上。