Keepalive in vue2 bereinigt den Speicher manuell, und es gibt ein Problem, dass der Sub-Routing-Speicher nicht zurückgefordert werden kann

Ursache

In letzter Zeit melden Kunden häufig das Problem von Systemabstürzen, insbesondere am Nachmittag. Nach einem Selbsttest stellte ich fest, dass der Systemspeicher nach dem Schließen des Tabs nicht wiederhergestellt wird. Ich habe mich bereits darum gekümmert. Nach dem Schließen des Tabs manuell clear the keep-alive Es sollte keine Speicherlecks im internen Cache geben, es scheint, dass es andere Caches gibt, die nicht bereinigt wurden.

Positionierungsproblem

1. Wiederherstellung der Szene

Das Projekt des Unternehmens ist eine Single-Page-Anwendung, und alle Vorgänge werden in einem Browser-Tab ausgeführt. Die gesamte Seite wird über Layou + Sub-Routing angelegt. Die Routing-Ebene erreicht Ebene 4, und das Geschäft ist komplex und umständlich. Muss eine reine Projektrestaurierungsszene neu aufbauen

2. Schreiben Sie eine Demo

Erstellen Sie ein Projekt mit vue-cli, [email protected],[email protected]

main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'
Vue.config.productionTip = false

new Vue({render: h => h(App),router
}).$mount('#app') 

app.vue

<template><router-view></router-view>
</template>

<script> export default {name: "App",
}; </script> 

Ansicht/Seite1, Ansicht/Seite2, Ansicht/A1, Ansicht/A2

<template><div>Page1<router-view></router-view></div>
</template>

<script> export default {name: "Page1",
}; </script>

<template><div>Page2<router-view></router-view></div>
</template>

<script> export default {name: "Page2",
}; </script>

<template><div>组件view A1</div>
</template>
<script> export default {name: "A1",data() {return {a: new Array(20000000).fill(1), //大概80mb};},
}; </script>

<template><div>组件view A2</div>
</template>
<script> export default {name: "A2",data() {return {a: new Array(20000000).fill(1), //大概80mb};},
}; </script> 

Ansicht/Layout.vue

<template><div><h1>Layout</h1><div class="box"><p>二级路由</p><router-link :to="{ name: 'A' }">A</router-link><br /><router-link :to="{ name: 'B' }">B</router-link></div><div class="box"><p>三级路由</p><router-link :to="{ name: 'AA' }">Page1</router-link><br /><router-link :to="{ name: 'BB' }">Page2</router-link></div><div class="box"><button @click="includeRemove()">清理keepalive缓存</button><br /><router-link to="/home">Home</router-link><br /></div><h1>keep-alive</h1>缓存页面:{
   
   { include }}<keep-alive :include="include"><router-view ref="alive"></router-view></keep-alive></div>
</template>

<script> export default {name: "Layout",data() {return {include: [],};},watch: {'$route'(val) {const name = val.meta.nameif (name && !this.include.includes(name)) {this.include.push(name);}}},methods: {includeRemove() {this.include = [];},},mounted() {},
}; </script>
<style> .box {margin-bottom: 20px;
} </style> 

router/index.js

import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)

const router = new Router({mode: "hash",routes: [{path: "/",redirect: "/home",component: () => import("../view/Layout.vue"),children: [{path: "home",component: () => import("../view/Home.vue"),},],},{path: "/a",component: () => import("../view/Layout.vue"),children: [{path: "a",name: "A",meta: {name: 'A1'},component: () => import("../view/A1.vue"),},],},{path: "/b",component: () => import("../view/Layout.vue"),children: [{path: "b",name: "B",meta: {name: 'A2'},component: () => import("../view/A2.vue"),},],},{path: "/a",component: () => import("../view/Layout.vue"),children: [{path: "page1",name: "Page1",component: () => import("../view/Page1.vue"),children: [{path: "a",name: "AA",meta: {name: 'Page1'},component: () => import("../view/A1.vue"),},],},],},{path: "/b",component: () => import("../view/Layout.vue"),children: [{path: "page2",name: "Page2",component: () => import("../view/Page2.vue"),children: [{path: "b",name: "BB",meta: {name: 'Page2'},component: () => import("../view/A2.vue"),},],},],},],
});

export defaultrouter 

laufendes Ergebnis

3. Reproduzieren Sie das Problem

Es ist ersichtlich, dass im Ausgangsfall die Speichernutzung etwa 7,7 MB beträgt

1. Nachdem Sie auf A und B geklickt haben, belegt der Speicher 168 MB

2. Klicken Sie auf Home, um sicherzustellen, dass das Routing beim Löschen des Caches nicht die Komponenten A und B belegt, und klicken Sie erneut, um den Keepalive-Cache zu löschen

Nach der manuellen GC wurde festgestellt, dass sich die Speicherauslastung auf 7,9 MB geändert hatte, was darauf hinweist, dass die Komponenten A und B erfolgreich freigegeben wurden. Dies simulierte die Situation, dass das Unternehmen in der frühen Phase des Projekts nur sekundäres Routing hatte. Das Problem des Systemabsturzes bestand nicht, was hier nur bestätigt wird.

3. Klicken Sie auf Seite 1, Seite 2, die Speichernutzung beträgt 168 MB

4. Klicken Sie auf Home und klicken Sie erneut, um den Keepalive-Cache zu löschen

Zu diesem Zeitpunkt ist ein Problem aufgetreten, der Speicher wurde nicht erfolgreich freigegeben, das Problem wurde gefunden

4. Analyse

Erfassen Sie zunächst die Speichernutzung im Ausgangsfall

Öffnen Sie Seite1 und Seite2, wechseln Sie zur Startseite, löschen Sie den Keepalive-Cache und zeichnen Sie den aktuellen Speicherabzug auf

Aus der Abbildung ist ersichtlich, dass die A1-Komponente noch vorhanden ist und von vue-router referenziert wird und nameMap alle Routing-Informationen speichert, sodass das Problem gefunden wird

Routing-Informationen im Ausgangszustand

Öffnen Sie Seite1 und Seite2, wechseln Sie zur Startseite und löschen Sie die Routing-Informationen nach dem Keepalive-Cache

Testen Sie eine andere Situation, wechseln Sie nicht zu Home, bevor Sie den Keepalive-Cache bereinigen, in diesem Fall kann der Speicher erfolgreich freigegeben werden.

5. Schlussfolgerung

1. Wenn die Registerkarte auf der aktuellen Route geschlossen und dann der Keepalive-Cache gelöscht wird, kann der Speicher normal recycelt werden
2. Wenn die inaktive Route auf anderen Routen geschlossen wird, können die Routing-Komponenten der zweiten Ebene normal recycelt werden, und die Speicherwiederherstellung der untergeordneten Routen ist abnormal. Vermuten, dass die Informationen in der inaktiven Route übereinstimmend geändert wurden. Schließlich handelt es sich um einen Singleton-Modus, was Sinn macht. Warum ist es normal, dass die aktive Route entfernt wird Zwischenspeicher?

3. Beheben Sie das Problem

1. Idee

1. Erhalte und schließe die aktuelle Tabulator-Routing-Eltern-Kind-Beziehung
. 2. Durchquere alle Routing-Informationen und lösche den instances.defaultWert des zugehörigen Routings

2. Spezifische Codeimplementierung

includeRemove() {this.include = [];// 为啥vue-router不开放直接获取nameMap的接口 淦const routes = this.$router.getRoutes()const nameMap = new Map()for (let index = 0; index < routes.length; index++) {const r = routes[index];nameMap.set(r.name, r)}// 假设我这边获取到了当前移除的tab页签,具体代码根据具体项目实现const rList = ['AA', 'BB']for (let index = 0; index < rList.length; index++) {const name = rList[index];const r = nameMap.get(name)if (r) r.instances.default = undefined}
} 

Führen Sie nach der Codeänderung den Vorgang erneut durch, die Speicherauslastung ist wie folgt und das Problem wurde erfolgreich gelöst

Zu guter Letzt

Kürzlich habe ich auch eine JavaScript- und ES-Notiz, insgesamt 25 wichtige Wissenspunkte, aussortiert und jeden Wissenspunkt erklärt und analysiert. Es kann Ihnen dabei helfen, sich schnell die relevanten Kenntnisse über JavaScript und ES anzueignen und die Arbeitseffizienz zu verbessern.



Freunde in Not, Sie können auf die Karte unten klicken, um sie kostenlos zu erhalten und zu teilen

Ich denke du magst

Origin blog.csdn.net/web22050702/article/details/128713589
Empfohlen
Rangfolge