先说一下环境:vue:2.5.2 vue-router:3.0.1 element-ui:2.13.0
最开始存在三个页面HelloWorld、foo和bar。
分别说一下这两个页面都有什么:
HelloWorld页面,有一个请求(会请求一些数据),将请求回来的数据放到data中,并用element-ui的select组件进行展示,另外就是一个跳转至foo页面的按钮,代码如下:
<template>
<div class="hello">
<el-button @click="getAccountListPage">
page获取科目列表
</el-button>
<el-select v-model="activeAcc" placeholder="请选择">
<el-option
v-for="item in accountPageList"
:key="item.id"
:label="item.codeAndName"
:value="item.id">
</el-option>
</el-select>
<el-button @click="goToFoo">
go Foo
</el-button>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
data () {
return {
activeAcc: '',
accountPageList: []
}
},
methods: {
getAccountListPage() {
let xmlhttp, that = this;
if (window.XMLHttpRequest) {
// IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
xmlhttp=new XMLHttpRequest();
} else {
// IE6, IE5 浏览器执行代码
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
let res = JSON.parse(xmlhttp.response);
if(res.result) {
that.accountPageList = res.value;
}
}
};
xmlhttp.open("POST","******这里是url*******",true);
xmlhttp.setRequestHeader("Content-type","application/json");
xmlhttp.send('{}');
},
goToFoo() {
this.$router.push({name: 'foo'})
}
},
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>
foo页面,很简单,有一个跳转至HelloWorld页面的按钮和一个跳转至bar页面的按钮,代码如下:
<template>
<div class="foo">
这是Foo页面
<el-button @click="goToHelloWorld">
go HelloWorld
</el-button>
<el-button @click="goToBar">
go Bar
</el-button>
</div>
</template>
<script>
export default {
name: 'Foo',
data () {
return {}
},
computed: {},
methods: {
goToHelloWorld() {
this.$router.push({name: 'HelloWorld'})
},
goToBar() {
this.$router.push({name: 'bar'})
}
}
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>
bar页面和foo页面一样,有一个跳转至HelloWorld页面的按钮和一个跳转至foo页面的按钮,代码如下:
<template>
<div class="bar">
这是Bar页面
<el-button @click="goToHelloWorld">
go HelloWorld
</el-button>
<el-button @click="goToFoo">
go Foo
</el-button>
</div>
</template>
<script>
export default {
name: 'Bar',
data () {
return {
}
},
computed: {},
methods: {
goToHelloWorld() {
this.$router.push({name: 'HelloWorld'})
},
goToFoo() {
this.$router.push({name: 'foo'})
}
},
}
</script>
<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped></style>
操作步骤:
1.进入HelloWord页面,不做任何操作,利用chrome浏览器开发者工具中的Performance monitor工具,查看内存使用情况
2.点击按钮获取数据,查看内存
可以看到,js、dom nodes、 js event,都有所增加。
3.跳转至foo页面,查看内存
这时候发现内存占用情况并没有明显变化,也就是说跳转foo页面后,helloword页面的内存并未得到释放。这是问题一。
4.这时候跳转至bar页面,查看内存
可以看到,刚刚存在的内存占用已经被释放了。这是问题二。
上面的截图都是我手动垃圾回收(collect garbage)后的截图。
对于上面出现的两个问题,还请各位大佬解答一下,万分感谢!!!
参考GPT和自己的思路:
首先,从截图上看,内存的增长基本都是由 DOM Nodes 导致的,因此我们可以考虑在路由切换时,手动销毁当前页面的 DOM 元素,以达到释放内存的目的。
其次,为什么在跳转至 foo 页面后,HelloWorld 页面的内存并未得到释放,是因为在跳转前,Vue 会将当前页面的组件实例缓存起来,以便在路由退回到该页面时,可以直接读取该实例,避免重新渲染的开销。因此,当前页面的内存并不会被彻底释放。
最后,为什么在跳转至 bar 页面后,之前的内存占用被释放,是因为从 HelloWorld 页面跳转至 foo 页面时,Vue 会将 HelloWorld 页面的组件实例缓存起来,当从 foo 页面跳转至 bar 页面时,Vue 会销毁 foo 页面的组件实例,并释放占用的内存,同时重新读取 HelloWorld 页面的组件实例,因此 HelloWorld 页面的内存占用没有得到任何释放。在跳转至 bar 页面时,Vue 会再次销毁 HelloWorld 页面的组件实例,并释放占用的内存,因此内存占用情况才会发生明显变化。