-
Notifications
You must be signed in to change notification settings - Fork 14
Description
Prerequisites
- I have read the Contributing Guidelines.
- I agree to follow the Code of Conduct.
- I have searched for existing issues that already report this problem, without success.
Stencil Store Version
2.0.16
Stencil Version
4.0.27
Current Behavior
Given a store instance that is shared between multiple components, any disconnected components can remain detached in memory until the store's dispose()
function is called.
Expected Behavior
A component with a shared store is able to be garbage collected when it's disconnected.
Steps to Reproduce
- Checkout the repo and switch to the
@stencil-store/disconnected-memleak
branch, if needed. - In the project, run
npm install
andnpm start
. - In the browser (e.g. Chrome 133), open devtools.
- In the viewport, click the Create my-global-counter button and optionally click the button that appears.
- Click the Destroy my global-counter button.
- Optionally repeat steps 4 and 5 a few times.
- Optionally wait 2s to give the store's internal clean-up logic to run.
- In the devtools Memory tab, click the Collect garbage button and note that no "Garbage collected" messages are logged despite the existence of a
FinalizationRegistry
inindex.html
. - Take a heap snapshot, search in the report for "counter", and note one or more
MyGlobalCounter
andDetached <my-global-counter>
entries exist.
Code Reproduction URL
https://github.com/nwhittaker/stencil-component/tree/%40stencil-store/disconnected-memleak
Additional Information
The store's elmsToUpdate
map looks to be what is retaining the component. Additionally, a couple issues appear to be at play preventing the map from being cleaned up in this scenario:
- Disconnecting a component doesn't trigger the store to run it's clean-up logic.
- When the store's clean-up logic does next run (e.g. on the next
set
), it doesn't identify the component as disconnected.
I don't know if using a WeakReference
for the component is feasible. It's also not clear to me why the isConnected
logic is checking for isConnected
on the component instance instead of the component's element:
If I naively wrap maybeElement
in the @stencil/core
getElement()
function, I'm able to resolve the 2nd issue that's preventing garbage collection.