React 16.8.6 版本存在內存洩露

blank

React 16.8.6 版本存在內存洩露

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

分析

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

blank

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

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

blank

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

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

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

blank

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

blank

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

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

blank

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

blank

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

blank

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

blank

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

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

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

blank
blank

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

blank

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

blank

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

結論

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

What do you think?

Written by marketer

blank

目標是最完善的微前端解決方案- qiankun 2.0

blank

深入理解Vue3 Reactivity API