在一个 Vue 应用程序中我遇到了内存泄漏,它发生的场景如下:
然而,分配的内存永远不会被释放,应用程序开始使用大约 30-40 MB 的 RAM,当渲染 v-for 时增加到 200 MB RAM(最终增加到超过 1GB 并在更多元素时崩溃浏览器添加或切换时)。当元素被移除时,它稳定地保持在 200MB(即使在手动垃圾收集时),所以它似乎保留了我的组件。
我尝试使用堆快照来定位问题,但它只显示一个子组件作为保留器。我找不到导致该组件未被垃圾收集的原因。我尝试使用
this.$root.off
取消订阅根目录上的所有事件监听器然而,这似乎根本没有帮助......代码本身是保密的,所以我不能只分享它,但是如果需要一些代码来理解这个问题,请告诉我,所以我可以提供一个复制的例子。
有谁知道我如何解决这个问题,或者有任何想法如何定位这个内存泄漏的原因?
更新
这是在 v-for 中呈现组件的组件:
<template>
<b-tabs card class="tabMenu" v-model="index">
<b-tab v-for="(tab) in tabs" @click="doSomething" @change="doSomething">
<TabComponent :tab="tab"></TabComponent>
</b-tab>
</b-tabs>
</template>
<script>
import TabComponent from "./TabComponent";
export default {
components: {
TabComponent,
},
created: function () {
this.$root.$on("addTab", this.addTab);
},
data: function () {
return {
tabs: this.$store.state.tabs,
}
},
beforeDestroy: function(){
this.$root.$off("addTab");
},
methods: {
addTab(tab) {
this.$store.commit("addTab", {tab: tab});
},
}
};
</script>
以及它呈现的选项卡组件:
<template>
<div @mousedown.stop>
<!-- Other components are loaded here but not relevant -->
<div>
<div v-show="conditionA">
<resize-observer @notify="doSomething" v-if="conditionC"></resize-observer>
<!-- This component renders many SVG elements which can be found in the heapsnapshot as DetachedSvgElements when the parent is not present anymore -->
<VisualizationComponent v-show="conditionD"
:tab="tab"></VisualizationComponent>
</div>
</div>
</div>
</template>
<script>
export default {
components: {
},
props: {
tab: TabObject,
},
data: function () {
return {
}
},
watch: {
// Some watchers
},
mounted: function () {
this.$nextTick(function () {
// Do some calculations
this.$root.$emit("updateSomething");
});
},
created: function(){
this.$root.$on("listen", this.doSomething);
// And listen to more events
},
beforeDestroy: function(){
this.$root.$off("listen");
// And unsubscribe all others
},
computed: {
// Quite a lot of computed props
},
methods: {
// And also many methods for data processing
}
}
</script>
最佳答案
我有一个类似的问题。我通过属性传递给下一个组件的对象在我的情况下是复杂且大的,我不知道您是否也是这种情况?
通过更改传递对象的方式解决了我的问题。通过将属性更改为数字(在我的情况下为 ID),我能够在使用该属性的组件中检索我的对象(基于 ID)。结果,我不必重复传递整个对象。由于某种原因,将大对象作为数据 Prop 传递并不能正常工作并导致奇怪的行为......
在您的情况下,当您不将 'tab' 属性直接传递给组件时,它可能会有所帮助,而是将此元素在商店中的位置索引,然后直接从组件内的商店中获取它。
因此,您需要将 v-for 更改为:
<b-tab v-for="(tab, index) in tabs" @click="doSomething" @change="doSomething">
<keep-alive>
<TabComponent :tabIndex="index"></TabComponent>
</keep-alive>
</b-tab>
在您的 TabComponent 中:
props: {
tabIndex: Number,
},
data: function () {
return {
tab: this.$store.state.tabs[this.tabIndex]
}
}
当然,这个原则也需要应用于任何做同样事情的子组件,以防止子组件中的任何内存泄漏,这显然也会影响到父组件。希望我能帮助你:)
关于javascript - 移除渲染组件时的 Vue 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59454894/