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,並查了相關文章,發現有不少人遇到這個問題:
- https:// github.com/facebook/rea ct/issues/16138
- https:// github.com/facebook/rea ct/issues/14732
- https:// github.com/facebook/rea ct/issues/18116
- Investigating Discord's React Memory Leak - Discord Blog
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以上。