这是一篇记录工做上所遇到的关于内存泄漏问题及如何解决的文章。前端
先大概描述一下个人问题:vue
技术栈: 框架:vue
组件库: ant design of vue
图表:g2
.web
项目需求: 在下图的看板中, 须要每20秒切换一次下面的两个小蓝点, 以达到切换并刷新图表的功能.前提是不用web socket
等轮询工具.chrome
下图的组件结构: switch-flex-chart
组件由 flex-chart
组件和 switch-icon-card
两个组件组合而成, 我经过给switch-icon-card
组件(也就是两个小蓝点) 添加一个定时器, 每20秒改变一下index
,而且回调给父组件 (switch-flex-chart
) 而后刷新并改变 flex-chart
组件里的图表数据.浏览器
形成的问题: 刚开始还好,可是若是时间久了,就会形成页面很是的卡顿, 但是在代码中, 我在生命周期-销毁阶段的里每次都会把定时器给清除并置为nullbash
这里轮询的功能我没有使用setInterval
,而是使用了两个setTimeout
:框架
<template></template>
<script>
export default {
created() {
this.init()
},
mounted() {},
data() {
return {
duration: 20000, // 多久刷新一次
_timer: null // 定时器
}
},
methods: {
init () { // 初始化
if (this.duration > 0) {
this._timer && clearTimeout(this._timer)
this._timer = null
this.polling()
}
},
autoPlay () { // 切换的函数
...
},
polling () {
this._timer = setTimeout(() => {
this.autoPlay()
this._timer && clearTimeout(this._timer)
this.polling() // 循环调用自身
}, this.duration)
}
}
}
</script>
复制代码
如上面的代码,我在每次轮询polling
的时候,都会使用clearTimeout
来清除一下定时器,可是我发如今你切换到其余页面的时候,定时器仍是在默默地执行着,因而我想到了在组件每次销毁的时候也必须把定时器也销毁:socket
destroyed() { // 生命周期-组件销毁
this._timer && clearTimeout(this._timer) // 先使用clearTimeout
this._timer = null // 最好将定时器也设置为null
}
复制代码
上面的方式解决了切换页面定时器还在运行的问题,可是仍是没有解决页面会很卡顿的状况。正常来讲就算定时器跑的再久也不会有这个问题。因此确定是有哪里形成了内存泄漏。函数
为了验证是否是这个缘由,我打开了chrome
的F12
控制台。而后找到了Memory
:工具
在这里你能够记录JavaScript
对象的堆快照,查找到内存泄漏。
此时我每10秒录制一个快照,分别对应Snapshot1-3
,发现JavaScript
对象的总大小一次比一次大,要不了一会个人浏览器就卡的不行了。
首先我想到的是否是图表内容没有清空,因此我在每次绘制g2
图表的时候先执行了一遍g2
内置的方法destory()
进行销毁。
<template></template>
<script>
export default {
created() {
this.init()
},
mounted() {},
data() {
return {
chart: null
}
},
methods: {
init () {
if(this.chart){ // 若是存在的话就销毁图表再从新生成
this.chart.destroy()
}
this.chart = new G2.Chart({
...
})
}
}
</script>
复制代码
觉得大功告成的我再次打开浏览器,发现内存泄漏的问题并无解决。因而我想这个图表对象是否是也要像定时器同样,在销毁的时候释放内存呢?
动手试试:
destroyed () {
this.chart.destroy()
this.chart = null
}
复制代码
处理完以后,我再次录制了三个快照,此次JavaScript
对象的大小没有再增加了,而且我页面挂在那半个小时也丝毫没有卡顿的迹象。
虽然问题解决了,但我还不是很清楚,为何在初始化的时候使用this.chart.destroy()
不可以释放内存,而非要使用设置成null
的方式。Google
了g2
的destory()
以后也是蹦出了一堆LOL
里的G2
...
在此也要感谢 OBKoro1 的倾囊相助。
参考文章: