Closed Mario34 closed 2 years ago
Snapshot 3 is generated after switching from '5000 items' to' Empty '. You can see that the number of separated nodes is basically the same as that on the page
same condition found
Transfered from Vue router and added a repro without it
This does not seem to be < component /> problem using v-if,there will still be memory leaks, see here: SFC Playground
I am experiencing the same issue in multiple projects I am working on using vue 3 with the router
Here is a link to @moushicheng 's example without the EmptyPage
component. This demonstrates that there is a memory leak in extremely simple cases when using v-if
. I tried with different Vue 3 versions and the results are all the same.
If you replace v-if with v-show, there is no memory leak.
Update: the fix only addresses the simplified cases here and here.
This is fixed in https://github.com/vuejs/core/commit/fc5bdb36ed429d6c3c956f373206ce75467adaf3
Some notes:
This is not technically a "memory leak". The root cause is that hoisted vnodes are retaining access to detached DOM nodes, and the detached DOM nodes in turn retain its parent / sibling trees. There is only one copy of the trees retained at any time, so the total memory does not increase over time even in the pre-fix behavior - thus not really a "leak", but does result in unnecessary memory cost.
This is not a regression and has been present in all versions of Vue 3.
Looks like the simplified reproduction is a bit different from the original case, where there is a legit memory leak that is still present in 3.2.40.
More investigation: the leak in the original repro is actually caused by the devtools. There is no leak in production.
The "leak" only happens when:
Vue Devtools buffers devtool-specific events in a global object before the devtools tab is activated. The buffered events hold references to the component instances triggering them, so those component instances, along with their DOM, are never released from memory until the devtools tab is activated and the buffer is cleared.
Although this does not affect production cases, it could cause perf issues when toggling between heavy components during development. It could also be confusing to users when debugging memory issues.
@Akryum this behavior seems to have been in devtools for a long time, I'm not sure if the memory issue is the result of a recent change or has always been there as well. Is there anyway we can rework this in the devtools to avoid it?
Minimal code needed to reproduce (using local global build):
<script src="https://unpkg.com/vue"></script>
<div id="app"></div>
<script>
const { ref, h } = Vue
const Foo = {
template: `
<div class="page">
<span v-for="i in 10">{{ i }}</span>
</div>`
}
const app = Vue.createApp({
setup() {
const ok = ref(false)
return () => {
return [
h('button', { onClick: () => (ok.value = !ok.value) }, 'toggle'),
ok.value ? h(Foo) : null
]
}
}
})
app.mount('#app')
</script>
@yyx990803 I believe the memory leak still exists, in prod, in the original case, without vue dev tools.
On a fresh install of Chrome, in private browsing, using the SFC link, here is a screenshot of the memory:
The memory will not grow beyond step 4, no matter how much you press the button. So it doesn't grow indefinitely, but it does retain memory that should be freed. This is a memory leak (not unbounded).
This is a huge problem when you have webpages with many big components - in this case, the memory retention resembles an unbounded memory leak because if each component retains its original size when it goes away, and double its size when it is shown for the second time, memory use will grow tremendously.
For instance, imagine you have an application where you can toggle between tables as a dashboard, where only 1 table is shown at a time. Each table uses 100mb. When no table is being shown, the application uses ~2mb of memory. When you show a table it uses 100mb. When you toggle the table and it goes away, it still uses 100mb when it should only use ~2mb. If you toggle the table multiple times, it uses up to 200mb at most. If you do this with multiple tables that are all different components, and imagine there are 20 tables/components, you will run out of memory and crash the tab, when at most the application should use 100mb while displaying a table.
@michaelperel The devtools are enabled on the SFC playground even in production mode.
@michaelperel What your are describing is exactly what @yyx990803 said in the previous comment:
Thank you so much for clearing that up! I figured because it said “prod” that it meant they were disabled.
Thank you all so much for your work on this issue, I really really appreciate it :)
thank you , help me a lot
Version
4.1.5
Reproduction link
github.com(has router) SFC PlaygroundSteps to reproduce
What is expected?
Stable memory usage
What is actually happening?
A large number of nodes are not reclaimed, and memory keeps growing