Memory not released when object is passed as prop in v-for loop
Version
3.2.19
Reproduction link
Steps to reproduce
- Create an array of objects
- Loop through the array with
v-for
and pass the current object as a prop to the child component - Empty the array
See minimal reproduction: Check chrome memory profiler. After forced garbage collection the Page class objects / children still remain in memory.
What is expected?
All children disappear and all the memory that was occupied by the objects inside the array is released.
What is actually happening?
The children disappear but the child instances are still in memory and holding on to the objects passed as props, not releasing the memory. This even happens when you don't do anything with the prop inside the child component, passing it in is enough to trigger the issue.
The issue seems to have been introduced in version 3.2.14. When I go back to 3.2.13 (tried 3.2.10 as well) the issue disappears and the memory is freed properly like expected.
Our use case is being able to switch between pdf's and looping through the pages to render them. Each page is a child component of the pdf viewer.
When switching between 4 pdf's, one after another and forcing garbage collection before taking the screenshots:
Vue 3.2.13 (expected, the last pdf was 20 pages long):
Vue 3.2.14+ (all previous pdf documents/pages are still in memory because the document and page are passed as props to the child components):
The only difference is the Vue version.
Interestingly this is caused by https://github.com/vuejs/vue-next/pull/4653, looking into it.
Update: can confirm this only happens in the dev build.
/cc @Akryum this is caused by the devtools emit buffer holding references to component instances. When the browser has no devtools installed, the buffer is kept forever so the unmounted instances are never released. This can happen in production too if the user has PROD_DEVTOOLS enabled.
The late injection seems to only happen in iframes, but the tricky part is we can't easily tell whether devtools is simply not installed, or that it's just not-yet-injected.
Ideally we want to know that there's just no devtools installed so it should not buffer anything. But the easy fix I can think of right now is a setTimeout to clear the buffer if the devtools is not injected after a certain period of time.
@yyx990803 Thank you for looking into this issue so quickly. Unfortunately the setTimeout fix doesn't seem to work. With Vue 3.2.20 memory still isn't released properly, even after waiting for a longer period than is set in setTimeout.
Both screenshots were after switching from a 123 page pdf to a 12 page pdf, waiting for a least 5 seconds, then forcing garbage collection.
Vue 3.2.13:
Vue 3.2.20: