React 16.8.6 版本存在內存泄露

發現這個React 內存泄露問題是某一天的晚上一直開着直播頁,直播頁用的 react 版本是 16.8.6,到了早上跳到這個頁面的時候,控制檯有點卡,懷疑是有內存泄露,於是就開始分析這個直播頁面。

分析

打開控制檯 performance 面板點擊開始錄製,如下:

從上圖可以發現在這時間內, nodes 節點一直在增長,很有可能發生了內存泄露。

我們來到 memory 面板分析內存變化:

注:上圖的藍色線條表示在時間軸的最後該對象依舊存在,灰色線條則說明對象在時間軸內被分配,但是已經被gc(垃圾回收)了。

上圖都是點擊 gc 再進行記錄的,但是上圖還有很多藍色線條,而且內存一直往上漲,很明顯的內存泄露問題,那會是什麼導致內存泄露的呢?

很快發現這裏有個 bi 的東西居然佔了 31%的大小:

這個 bi 是用來幹嘛的?展開 bi ,鼠標懸浮在 bi 某處:

發現這個節點是直播間裏的進房消息,裏面是 react 存的 FiberNode 節點,觀察了一下里面這些 bi 基本上都是消息元素。

選擇 summary,選出Detached (分離)的元素:

Detached HTMLDivElement 居然有41429個,展開,鼠標懸浮:

還是消息信息,說明是這個導致 bi 增加的。我們繼續展開:

從上圖看 react 會保留消息的上下兄弟節點的引用,而且保留的引用層級有點深,各個節點嵌套依賴,導致一直存在內存裏:

仔細查下了項目消息相關代碼,發現並不會存在有內存泄露的操作。這裏簡單說下渲染消息的邏輯,消息有進房消息,聊天消息,禮物消息等等,消息展示會根據 messages 數組裏面的類型去渲染不同的消息。messages 數組不會無限增長,控制在 100 個,超過就刪掉第一個元素,保證維持100個元素渲染消息,但是從上圖來看,這些分離的元素並沒有被 react 完全刪除,還保存在內存裏,查了下 React 的 Issue,並查了相關文章,發現有不少人遇到這個問題:

React 核心成員 Dan 給出的解決辦法是升級到 16.9.0。

這裏將項目 React 和 React-dom 版本升級16.9.0,
發現 FiberNode 節點還是會一直增加。。。

繼續查看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 節點:

發現 node 節點可以降下來了,查看 memory 面板:

對比Snapshot 5,分離的元素沒有新增,說明這個版本基本修復了這個問題。

結論

React 16.8.6 (16.2.5到16.12.0 可能會有,這些版本沒有驗證,但是 issue 裏面有人遇到)的版本會存在內存泄露問題,建議升級 React 到 16.13.0 以上。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章