React: [Umbrella] Memory Leaks

Created on 9 Jul 2019  路  6Comments  路  Source: facebook/react

This issue is a summary of issues mentioned in https://github.com/facebook/react/pull/15157.

There are many different ways to create memory leaks with React since we give you access to the imperative power to do so. Most should be dealt with by clean up / unmount functions.

Some could be pure React bugs. Some could be related to the lack of clean up of render phase effects. Others could be related to leaks that exists but the way React works makes them larger than they otherwise would've.

Resolved

  • [x] Land https://github.com/facebook/react/pull/16115 What patterns are actually covered? It can cut down on a potentially larger leak but is that the whole leak? I could imagine some patterns where this is the complete solution but unclear if it's the complete solution for the patterns that people are actually hitting in practice.

Actionable

I think there are at least two actionable patterns to address from #15157:

  • [ ] If a handle on a DOM node is leaked, it takes the React tree with it. This is a fairly easy mistake to make and the effect is pretty high. What we would do here is special case DOM nodes with refs on them, and always detach their back pointer to the React Fiber, if it was ever fully mounted. We currently traverse these trees anyway when they get deleted. We want to stop doing this for most things but for nodes with a ref it seems minor to special case since they typically need to be invoked with null anyway.
  • [ ] Investigate the source of the leak in https://github.com/jonnycornwell/potential_react_leak and fix the source of the problem.

Unresolved

  • [ ] Closing over setState/dispatch or class component instances to global state can leak too. Does this pattern warrant special casing too? Under what conditions?
  • [ ] It appears Chrome (and maybe other browsers?) may retain inputs due to the Undo Stack (https://github.com/facebook/react/issues/17581)
  • [ ] What other issues remain after solving the actionable above? Let's make another pass investigating if people's original issues remain.

Won't Fix

  • Side-effects in class constructor, componentWillMount, componentWillReceiveProps, componentWillUpdate, getDerivedStateFrom... and render that store a reference to anything stateful outside React won't be able to clean up. This is documented in the 16.3 release and is a major design decision as part of the concurrent/suspense/error handling strategy.
  • Effects/state retained temporarily in alternate fiber likely won't be fixed short term. This is due to how Fiber uses two trees and swaps between them. This can lead to additional values being retained until that tree gets some work on it to swap again. This was observed in the Hooks release and there are some confusing cases where a destroy function can hold onto more memory than expected in the closure. Typically this is solved by using a custom hook since that gets its own scope/closure.
  • Props/child trees retained by alternate children. Similarly, children that was just removed can sometimes between retained by the alternate copy of that. That is until that node gets another update on it which clears out the old children. These cases are fairly unusual and fix themselves eventually as the app lives on.
React Core Team

Most helpful comment

Is there an estimate for when #18814 or other workarounds to the leaked-DOM-leaking-React trees issue will be picked back up?

I'm also hitting the issue where DOM nodes are retained in Chrome, but I haven't been able to track down exactly why

All 6 comments

@matthewbryancurtis You are using CodeSandbox which runs React in development mode and includes a ton of other code. Can you please create a React-only demo in production mode? Thanks.

If GC cleans it up, then it's not a memory leak, is it?

Sorry, my misunderstanding. I'll go ahead and delete my comments to reduce noise on this issue.

Regarding

If a handle on a DOM node is leaked, it takes the React tree with it ... What we would do here is special case DOM nodes with refs on them, and always detach their back pointer to the React Fiber, if it was ever fully mounted

In #17581 I suggest that most if not all input nodes are retained by the browser; in which case React might want to detach fibers from all input nodes as well, not just nodes with refs. These leaks are occurring automatically and are not necessarily caused by developer error.

Do we think this should be prioritized? I'd be happy to contribute, though I'm not familiar at all with the unmounting/cleanup cycle and would appreciate some guidance 馃檱

@albertxing I think I'm seeing the same memory leak issue as you here. I have DOM input nodes being held by Chrome seemingly indefinitely after they're unmounted, and those are retaining huge amounts of memory via memoizedProps etc. It's causing me some big problems. Did you make any progress on this?

Is there an estimate for when #18814 or other workarounds to the leaked-DOM-leaking-React trees issue will be picked back up?

I'm also hitting the issue where DOM nodes are retained in Chrome, but I haven't been able to track down exactly why

Was this page helpful?
0 / 5 - 0 ratings