vue2 のキープアライブは手動でメモリをクリーンアップし、サブルーティング メモリを回収できないという問題があります。

原因

最近、お客様から、特に午後にシステムがクラッシュするという問題が頻繁に報告されます. セルフテストの結果、タブを閉じた後にシステムメモリが回復しないことがわかりました. 私はすでに対処しました. タブを閉じた後, 手動でキープアライブをクリアする 内部キャッシュにメモリ リークはないはずですが、クリーンアップされていないキャッシュが他にもあるようです。

ポジショニングの問題

1.シーンの復元

同社のプロジェクトは単一ページのアプリケーションであり、すべての操作はブラウザー タブで実行されます. ページ全体は Layou + サブルーティングによってレイアウトされます. ルーティング レベルはレベル 4 に達し、業務は複雑で面倒です. 純粋なプロジェクトの復元シーンを再構築する必要がある

2. デモを書く

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> 

ビュー/ページ1、ビュー/ページ2、ビュー/A1、ビュー/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> 

ビュー/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> 

ルーター/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 

実行結果

3. 問題を再現する

最初のケースでは、メモリ使用量が約 7.7MB であることがわかります。

1. A と B をクリックした後、メモリは 168MB を占有します

2. [ホーム] をクリックして、キャッシュをクリアするときにルーティングがコンポーネント A と B を占有しないようにし、もう一度クリックしてキープアライブ キャッシュをクリアします。

手動 GC の後、メモリ使用量が 7.9MB に変化したことがわかり、コンポーネント A と B が正常にリリースされたことを示しています.これは、プロジェクトの初期段階で会社がセカンダリルーティングしか持っていなかった状況をシミュレートしました.システムクラッシュの問題は存在しませんでした。これは、ここで確認されたばかりです。

3. Page1、Page2 をクリックします。メモリ使用量は 168MB です。

4. [ホーム] をクリックし、もう一度クリックしてキープアライブ キャッシュをクリアします。

このとき問題が発生しました、メモリが正常に解放されませんでした、問題が見つかりました

4. 分析

最初のケースで最初にメモリ使用量を記録します

Page1 と Page2 を開き、ホームページに切り替え、キープアライブ キャッシュをクリアし、現在のメモリ スナップショットを記録します。

図からわかるように、A1 コンポーネントはまだ存在し、vue-router によって参照されており、nameMap はすべてのルーティング情報を保存しているため、問題が見つかりました。

初期状態のルーティング情報

Page1 と Page2 を開き、Home ページに切り替え、キープアライブ キャッシュの後にルーティング情報をクリアします。

別の状況をテストします。キープアライブ キャッシュを消去する前にホームに切り替えないでください。この場合、メモリは正常に解放されます。

5。結論

1. 現在のルートでタブが閉じられ、キープアライブ キャッシュがクリアされた場合、メモリは正常にリサイクルできます.
2. 非アクティブなルートが他のルートで閉じられた場合、第 2 レベルのルーティング コンポーネントは正常にリサイクルされます.と下位ルートのメモリ回復が異常 , 非アクティブなルートの情報が一致したと推測. 結局、それはシングルトンモードです. アクティブなルートが削除するのはなぜ正常ですか?キャッシュ?

3. 問題を解決する

1.アイデア

1. 現在のタブ ルーティングの親子関係を取得して閉じる
2. すべてのルーティング情報を通じて、関連するルーティングのinstances.default値をトラバースして削除する

2. 特定のコードの実装

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}
} 

コード修正後、再度プロセスを実行すると、メモリ使用量は次のようになり、問題は正常に解決されました

やっと

最近では、JavaScript と ES のノート、合計 25 の重要な知識ポイントも整理し、各知識ポイントの説明と分析を行いました。JavaScript と ES の関連知識をすばやく習得し、作業効率を向上させるのに役立ちます。



困っている友達は、下のカードをクリックして無料で受け取り、共有できます

おすすめ

転載: blog.csdn.net/web22050702/article/details/128713589