1. 内存泄漏是什么
内存泄漏是变量不再被使用本来应该被释放了,但是因为不合理的引用导致没有被释放,占用了一定的内存,甚至导致内存暴涨,进而程序崩溃。
2. 如何排查内存泄漏
查看浏览器的标签页
鼠标经过浏览器的标签页会出现内存用量的提示,如果浏览器出现了内存泄漏,能在这里很直接的看出来,在某个时间点之后内存涨了
浏览器的任务管理器
这里能够看到某个操作进行的同时,内存发生的变化,进而侦测内存泄漏,如果切换到某个页面或者某个操作之后,内存增加了非常多,则可能是出现了内存泄漏
浏览器的Memory工具
通过多次操作+打快照的对比,能够看出是否发行内存泄漏。右侧能够看到代码内存占用的情况
注意,垃圾回收机制我们无法代码直接控制,但是打快照时,我们可以直接点击按钮触发垃圾回收,再打快照或者看任务管理器,看看是否会下降
3. 内存泄漏排查
3.1 代码定位
- 首先,最好能明确这真的是内存泄漏,还是只是正常现象。比如从A页面切换到B页面,内存是40MB,再切换到A,再切回B,此时变成了50甚至是80、100MB,这可以视为一种内存泄漏,可能是页面销毁时东西没有清理干净
- 其次,可以通过return代码,定位到具体的代码
3.2 对象体积
数组或者对象的体积会影响到内存,尤其是后端返回10000+以上的数据, 此时多一个属性可能会多很多内存,把不需要的剔除出去
data[i].children.push({
id: `${i}-${j}`,
path: `/${i}-${i}`,
name: `test-${i}-${j}`,
children: [],
showChildren: false,
height: 180,
- weight: 60,
- gender: 'boy',
- hobby: 'gaming'
});
3.3 闭包
闭包会导致内存泄漏,尤其是这个变量还很大的时候,如下arr本来是局部变量,但是在全局访问到了,他则不会被删除掉,不需要时记得清空他
function closure () {
let arr = new Array(200000).fill(null).map(e => new MyObject())
return function () {
let arr2 = arr
}
}
let arr = closure()
arr = null // 执行,才能清空变量
3.4 用到的定时器,事件监听,echarts图表在切换页面后记得清空一下
onUnmounted(() => {
clearInterval(timer.value);
window.removeListener('click', fn)
myChart.value.dispose()
})
3.5 删除不必要的console.log
如果console.log打印了很大的变量,可能也会导致内存泄漏
3.5 axios使用cancelToken
如果从点击进入A页面,立马切换到B页面,此时A页面的接口可能已经发出去拿数据了,这也会占用内存。我们可以把cancelToken存储在store里面去
const { isCancel } = axios
service.interceptors.request.use(
config => {
let CancelToken = axios.CancelToken;
let source = CancelToken.source();
// getters里面没有token,
if(!store.getters.initCancelTokenSource){
store.dispatch("modCancelToken",source)
config.cancelToken = source.token
}else {
// getters里面有token
config.cancelToken = store.getters.initCancelTokenSource.token
}