概述
最近在開發 Vue 項目的時候遇到了內存泄漏問題,記錄下來,供以后開發時參考,相信對其他人也有用。
背景
背景是需要用 three.min.js 和 vanta.net.min.js 給首頁加上動畫效果。
內存泄漏
我們的代碼是這樣的:
mounted() {
this.loadScript('/js/three.min.js', () => {
this.loadScript('/js/vanta.net.min.js', () => {
this.bannerBg = window.VANTA.NET({
el: '#bannerBg',
color: 0x2197F3,
backgroundColor: 0x071E31,
});
});
});
},
methods: {
loadScript(path, callback) {
const script = document.createElement('script');
script.src = path;
script.language = 'JavaScript';
script.onload = () => callback();
document.body.appendChild(script);
},
},
這樣就導致,在每次首頁加載的時候,都會去請求 three.min.js 和 vanta.net.min.js 靜態資源,並且初始化。然后由於組件銷毀的時候並沒有清除 window.VANTA.NET 方法施加的內存,所以導致了內存泄漏。具體表現是,切換首頁和其它頁,切換的次數多了的話,就會卡住。
那一般的方法是直接在 beforeDestroy 生命周期里面 執行 this.bannerBg.destroy() 就行了。但是一開始我並不知道 this.bannerBg 帶有destroy 方法,所以走了下面的不少彎路。
檢查內存泄漏
按照官網的方法,Mac 下打開 Chrome 任務管理器的方式是選擇 Chrome 頂部導航 > 窗口 > 任務管理;在 Windows 上則是 Shift+Esc 快捷鍵。則可以打開 Chrome 的任務管理器,主要查看 Browser 和 GPU Process 的 內存占用空間。前者是查看程序執行所消耗的內存,后者是查看動畫效果所消耗的內存。
keep-alive
如果插件本身沒有提供 destroy 方法的話,可以使用官方的替代方案:使用 keep-alive 組件,在內存中保留組件的狀態。示例代碼如下:
<keep-alive>
<my-component v-if="show"></my-component>
</keep-alive>
但是我實際使用下來,並沒有用,估計是因為 three.js 生成的 WebGL 動畫導致的不是 Browser 的內存泄漏而是 GPU 的內存泄漏吧。
如果這種方法不行的話,估計就真沒辦法避免內存泄漏了,幸好 vanta.net 其實暴露了 destroy 方法!
我看了下和這個場景比較相似的vue-particles源碼,它竟然沒有使用 destroy 釋放內存!!!
一個坑
在解決的過程中,我碰到了一個坑,就是我原本以為在 mounted 生命周期內的程序不會影響渲染,因為當執行到 mounted 生命周期的時候,Dom已經掛載好了。但是其實我錯了,如果在 mounted 生命周期里面執行一段非常耗時的代碼,瀏覽器是會一直白屏的,代碼示例如下:
mounted() {
let a = 1;
while (a < 123456) {
console.log('aaaaa', a);
}
}
原因我暫時不知道。。。。。。。。