-
Notifications
You must be signed in to change notification settings - Fork 51k
Bug: [Fiber] Apps that have data-heavy props or state use hundreds of MBs of extra memory #36176
Description
Hello!
I'm a frontend engineer at Grafana, currently investigating excessive/unexpected memory usage.
Grafana is very data-heavy, users run arbitrary queries against databases, and it all ends up in the browser. The existing architecture and plugin/extension ecosystem of Grafana relies on passing this data through a prop to the panel components. We cannot break this contract, so pulling the data out of React props/state is not possible without breaking an enormous amount of existing code that relies on this contract / API.
This was raised back in 2018 in #14380, with tl;dr that this was a known design tradeoff of Fiber. however, the issue was stale-closed with no definitive statement from the core team whether this behavior is something that cannot be mitigated.
I don't know the details of the implementation, but it seems odd that once rendering has settled that the old fiber state cannot be released so it can be effectively GC'd.
React version: 16+ (every version after Fiber replaced the Stack reconciler)
Steps To Reproduce
- Put heavy data (such as a db query response) into props, context, state, memo, reducer
- When new data replaces old data, the old data remains in memory, causing double the resident memory to be used.
Link to code example:
It appears that the only way to avoid this is to create custom state hooks that internally rely on useRef. and only pass around refs when prop-drilling. i've been playing with these workarounds here: https://github.com/leeoniya/react-memory.
Another approach that works - and is nasty - is to rely on a usePrevious hook to grab and clear the previous data by mutation, like resetting previous data arrays via values.length = 0.
I really want to avoid introducing unusual hooks and non-idiomatic React patterns to our codebase to work around this issue, but i'm not currently seeing a good way to avoid this. Would love some advice, or at least to understand if things will remain this way for the foreseeable future so we can make the right decision.
The current behavior
2x memory
The expected behavior
1x memory