這是一篇記錄工做上所遇到的關於內存泄漏問題及如何解決的文章。前端
先大概描述一下個人問題: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 的傾囊相助。
參考文章: