fix: stops memory leak from ContextMenu by fixing endless render loop #295
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Closes #278
Summary
There is a memory leak in the app where the
WebView2
would hit 2gb of Ram and trigger the "This page is having a problem". I found references toWebView2
having memory leaks in Tauri via Google searches, and on Windows platform Tauri is using Microsoft Edge as it's WebView. I couldn't confirm if Mac users were experiencing this bug or not. I was able to reproduce the problem on Windows by opening multiple projects and leaving the app running.Here we can see memory increasing at a rate of 1mb/s while the app is idle.
rivet-memory.mp4
I started debugging the leak by removing large chunks of code from the Rivet app until the leaks stopped. This process revealed the leaks to be coming from inside
<NodeCanvas>
component. There I narrowed the problem down to the<ContextMenu>
.I concluded by assumption that
@floating-ui/react
is the source of the memory leaks, and found these refs to people discussing memory leaks with the library. We use this library for positioning the popup context menu, and in addition wrap the<ContextMenu>
inside a<CssTransition>
which keeps the component in the DOM even when it's not visible.Memory Leak references:
floating-ui/floating-ui#2576
floating-ui/floating-ui#744
These things combined to create a problem, because
<ContextMenu>
was stuck in an endless render loop. Since<CssTransition>
keeps it in the DOM and@floating-ui/react
leaks memory with each render, then the render loop was causing the 1mb/s leak.Here we can see the render loop:
rivet-memory2.mp4
I traced the render loop down to the
useContextMenuAddNodeConfiguration()
hook where it usesuseAsyncEffect()
to get theuiData
for the menu. The async hook would callsetUiData()
when done, this would trigger another render and the hook would fetch all the uiData again and callsetUiData
again in an endless loop.The fix ended up being the use of a dependency array on the hook. Once applied the memory leaks stopped, and I also moved the
constructors
variable outside of the hook as it's an external dependency.