preact
preact copied to clipboard
Preact causes memory leak on useState?
I have spotted memory growth in a performance benchmark. I have compared the same benchmark app with react. React clears memory when a component with useState is unmounted. Preact holds the state value after unmount:
I am not sure about the cause and if it is expected behaviour, but it definitely spoils performance comparison results for Preact and probably a red flag, which is worth investigating further.
Here is how to reproduce it:
-
Clone https://github.com/avkonst/js-framework-benchmark
-
npm install
-
npm start (notice webserver started, if it does not start check prerequisites here: https://github.com/avkonst/js-framework-benchmark)
-
cd ./frameworks/keyed/preact-hookstate
-
npm install
-
npm run build-prod
-
open crome at http://localhost:8080/frameworks/keyed/preact-hookstate/
-
open development tools, memory tab
-
take heap snapshot using chrome devtools
-
click "Create 1000 rows"
-
take heap snapshot using chrome devtools
-
click "Clear"
-
take heap snapshot using chrome devtools
-
go to snapshot 2 and setup comparison with snapshot 1
-
notice an object with 2001 allocations (this is the Hookstate state link referencing the state variable placed into useState)
-
go to snapshot 3 and setup comparison with snapshot 2
-
notice only 1 state link deleted, although it is expected 2001 are deleted, at least eventually.
-
retantion tree for the state variable from useState() call is looking strange, I can not interpret much here:
I can see that React also retains states after component is unmounted, but it get's cleaned up eventually. I.e. if I run create/clear many many times in a loop, React releases states and you can see that about 1000 states are retained (about 4MB). If I run it many times with Preact, it retains all states from past mounted and unmounted components (I even reached 70MBs by doing this in cycle).
BTW, if you are interested in to see how React compares with Preact on the benchmark with Hookstate, have a look here: https://github.com/avkonst/hookstate/issues/14#issuecomment-585023323
Excellent analysis. A few initial guesses at the culprit here:
- circular references in the virtual DOM tree (
vnode._parent
🔁vnode._children[0]
) -
component._hooks
being attached to those vnodes asvnode._component.__hooks
Hey @avkonst
Thanks for the awesome explanation, we can validate point two made in the above reply by doing
yarn add https://github.pika.dev/preactjs/preact/pr/2337
I'll try this tonight or if you have time before I do feel free to report it! Thanks again for this awesome issue
Hmm another circular reference is: (assuming c.__hooks._list[0]
is the useState
hook) component.__hooks._list[0]._component == component
. Could that impact this?
@kiranmarshall Please file a new issue. The problem you're describing is unrelated to memory growth.
@marvinhagemeister I ended up finding the issue and it was a totally unrelated. PEBCAK-ing hard, as usual. Thanks anyway!