javascript - 移除渲染组件时的 Vue 内存泄漏

标签 javascript vue.js memory-management memory-leaks vuex

在一个 Vue 应用程序中我遇到了内存泄漏,它发生的场景如下:

  • 我们有一个在 v-for 中呈现的组件,其中包含许多子组件
  • 当从数组中删除相应的元素时,v-for 会重新渲染这些组件并正确删除与从数组中删除的元素对应的组件。

  • 然而,分配的内存永远不会被释放,应用程序开始使用大约 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/

    相关文章:

    c - 函数内部重新分配 - 损坏的大小与 prev_size

    PHP [面向对象] : Memory allocation for Inheritance

    javascript - 如何启用和禁用 Twitter Bootstrap 按钮?

    javascript - 验证总是验证失败

    javascript - 如何使用传单图表在 reactjs 中显示数组中的标记

    javascript - 我什么时候应该使用 Vuex?

    javascript - 哪个是在 vue js 中将数据组件传递给组件的最佳方式

    vue.js - 使用 Vuex 突变更新对象引用的正确方法是什么?

    C malloc() 数组即使在被访问后也不会占用内存

    javascript - 如何删除模态打开时自动添加的额外水平滚动条?