JedWatson / react-select

The Select Component for React.js
https://react-select.com/
MIT License
27.63k stars 4.13k forks source link

Memory leak in react-select #5635

Open Sh1d0w opened 1 year ago

Sh1d0w commented 1 year ago

When using react-select, after the component is destroyed by e.g. not rendering it or more realistic example by page navigation, it leave a detached nodes that can not be garbage collected because they are not freed properly somewhere.

Link to reproduce: https://codesandbox.io/s/blissful-dream-l22yoq?file=/src/App.js How to reproduce: https://learn.microsoft.com/en-us/microsoft-edge/devtools-guide-chromium/memory-problems/dom-leaks

Steps:

  1. Open https://l22yoq.csb.app/
  2. Open devtools -> Detached elements and click Get Detached Elements button. Observe there are no detached elements
  3. click on the select and choose randomly options
  4. click the hide button below the select to stop rendering it
  5. click Get Detached Elements button in the devtools
  6. click collect garbage button to force GC
  7. click Analyse button to analyse the current heap snapshot
  8. see there is item that is still referenced, check the last column where you have @somenumber value

Video:

https://github.com/JedWatson/react-select/assets/5074917/10a281ae-10f6-4528-b07f-7545484129e5

Expected behaviour:

When react-select is no longer rendered it should not leave detached elements, as they pile up and cause a memory leak.

Rall3n commented 1 year ago

Hello @Sh1d0w,

I could not reliably reproduce the issue you mention.

Only once did I find a detached element retained in memory, but this one time it was kept by internal react code, and not react-select.

Does this also happen in a production build?

Sh1d0w commented 1 year ago

Hi @Rall3n , thank you for taking look into this.

It is weird that you do not reproduce it, for me it happens every time I try the steps exactly as seen in the video. Try selecting several options before you hide it.

Yes it happens on production, that is actually the reason I tried to dig into the issue. After several hours being on our website, it slows down. I've observed the memory has increased gradually over time. So I've started doing some heap testing. It is quite hard as the app is quite large and complex, so my first strategy was to test each of the third party libraries we use in isolation. Thats why I've created the code sandbox env with one of each libraries so I can test them in isolation.

I am still learning how to debug memory leaks in React, thus I wasn't able to pinpoint the exact reason for it yet, nor I am familiar with react-select codebase too. I guess it could be some ref hanging after the component is destroyed or event listener not properly detached.

I've also looked in React repo for clues as well to make sure the bug is not on their side, so far I've found only

https://github.com/facebook/react/issues/23214 and https://github.com/facebook/react/issues/25772 , but not sure if they are the root cause here since I couldn't find any reference to contentEditable in this repo source code.

haldunanil commented 1 year ago

I also ran into this issue and reproduced it here:

https://github.com/haldunanil/react-select-memory-leak-demo

Here's the Performance tab in local dev:

Screenshot 2023-08-17 at 1 58 07 PM

And here it is running in production mode using vite preview:

Screenshot 2023-08-17 at 2 02 25 PM

Notice that in the second instance, the memory usage didn't go down at all until I waited around 10s and reopened the menu, at which time it went down on close.

piskunovim commented 1 month ago

We also encountered this problem in our project. Each opening of options leads to the garbage collector not collecting data from the heap and the detached node elements are not removed either. Is there any information regarding this issue?