.unmount() memory leak
Version
3.0.4
Reproduction link
http://wagoon.demoeshop.net/test-remove-vue.html
Steps to reproduce
- click first button to create new Vue app
- click second button to unmout it (and delete all pointers to that app)
- call garbage collector in chrome dev tools
- create memory snapshot (app is still in memory linked from vue_app)
What is expected?
According to doc, .unmount() in VUE3 is replacement for $destroy in vue2 => this method should destroy all app data to avoid memory leaks Accordigt to 990803, unmounted app is not allegible for new mount(), so there is no need to store anything aboth it in memory (https://github.com/vuejs/vue-next/issues/1287#issuecomment-638252620)
What is actually happening?
App object stays linked from vue_app and cant be collected with garbage collector
Only solution i found is removing the target DIV from DOM I descrobed all steps in detail on stackoverflow post https://stackoverflow.com/questions/65475604/vue-js-3-unmount-and-memory-leak
Same problem. I need to dynamically create lots of vueApp in my project, and I use js-lru to cache, as they are evicted from the cache, I unmount and delete, but it doesn't help.
"According to doc"... The migration guide does not state that unmount()
is a replacement, just that $destroy
has been removed, and that Vue instances should not be managed manually. Which is weird, because sometimes you need to.
I'm having exactly this problem, but in the server side... Once createSSRApp(App, fetchedData) for each request, it 's keeping me in memory the fetchedData.
App.js
import { createSSRApp } from 'vue';
import App from '../src/App.vue';
import PageStore from '../src/store/Brands.js';
import CommonStore from '../src/store/Common.js"';
import { createI18n } from 'vue-i18n';
import { createStore } from 'vuex';
export function getApp(fetchedData) {
const modules = { ...CommonStore.modules, ...PageStore.modules };
const storeOptions = { modules };
const store = createStore(storeOptions);
const app = createSSRApp(App, { fetchedData })
.use(store)
.use(i18n);
return app;
}
entry-server.js
import { basename } from 'path';
import { getApp } from './app';
import { renderToString } from '@vue/server-renderer';
export async function render(data, ssrManifest, manifest, client, dist) {
const { app } = getApp(data);
const ctx = {};
const html = await renderToString(app, ctx);
const preloadLinks = ssrManifest ? renderPreloadLinks(ctx.modules, ssrManifest, dist) : '';
const { entry, links } = manifest && client ? renderLinks(manifest, client, dist) : { entry: '', links: ''};
return [ html, preloadLinks, entry, links ];
}
entry-client.js
import { getApp } from './app';
const data = window.__INITIAL_STATE__;
const { app } = getApp(data);
app.mount('#app');
As we can't unmount an app that it isn't mounted, the only solution that I found for the moment is create the createSSRApp once, and in each request overwrite the SSR context. But this is not a real solution, because we can have cross request state pollution...
the image is a snapshot after 5 requests:
Array @3942577 Array @4259791 Array @4310869 Array @4422637 Array @4448451
The five Array objects are equal in each case.
Am I doing something wrong ?
I'm having exactly this problem, but in the server side... Once createSSRApp(App, fetchedData) for each request, it 's keeping me in memory the fetchedData.
App.js
import { createSSRApp } from 'vue'; import App from '../src/App.vue'; import PageStore from '../src/store/Brands.js'; import CommonStore from '../src/store/Common.js"'; import { createI18n } from 'vue-i18n'; import { createStore } from 'vuex'; export function getApp(fetchedData) { const modules = { ...CommonStore.modules, ...PageStore.modules }; const storeOptions = { modules }; const store = createStore(storeOptions); const app = createSSRApp(App, { fetchedData }) .use(store) .use(i18n); return app; }
entry-server.js
import { basename } from 'path'; import { getApp } from './app'; import { renderToString } from '@vue/server-renderer'; export async function render(data, ssrManifest, manifest, client, dist) { const { app } = getApp(data); const ctx = {}; const html = await renderToString(app, ctx); const preloadLinks = ssrManifest ? renderPreloadLinks(ctx.modules, ssrManifest, dist) : ''; const { entry, links } = manifest && client ? renderLinks(manifest, client, dist) : { entry: '', links: ''}; return [ html, preloadLinks, entry, links ]; }
entry-client.js
import { getApp } from './app'; const data = window.__INITIAL_STATE__; const { app } = getApp(data); app.mount('#app');
As we can't unmount an app that it isn't mounted, the only solution that I found for the moment is create the createSSRApp once, and in each request overwrite the SSR context. But this is not a real solution, because we can have cross request state pollution...
the image is a snapshot after 5 requests:
Array @3942577 Array @4259791 Array @4310869 Array @4422637 Array @4448451
The five Array objects are equal in each case.
Am I doing something wrong ?
Nevermind the problem was vuex.
Hi @andoniabedul , How did you figure out that the problem was Vuex?
What did you do to solve the issue in that case?
Thanks in advance
Hi @gquinteros93 I solved the problem adding a devtools: false
in the app.use of vuex when is production.
Sorry for the delay answering I didn't read the notifications.