這是我參與8月更文挑戰的第5天,活動詳情查看:8月更文挑戰**node
最近在寫小程序的過程當中,用到了不少的console.log
,開始是爲了聯調方便,一直沒有刪除,致使頁面時不時有卡頓現象出現,開始以爲頁面從新刷新就行了,可是產品和測試不會答應的呀,後來排查了一下問題,才發現頁面中出現不少種內存泄漏,想起以前面試時候這個問題也是考了不少次,一直沒有總結,今天就趁機總結一下也好提醒本身平時多多注意。面試
首先咱們得清楚什麼是內存泄漏,在引擎中有垃圾回收機制,主要針對一些程序中再也不使用的對象,清理回收釋放掉內存,可是實際上垃圾回收機制並不會把再也不使用的對象所有回收掉。所以咱們在代碼中要主動避免一些不利於引擎作垃圾回收的操做,這些沒有被及時回收的對象內存,咱們叫它內存泄漏(Memory Leak)。小程序
來看看一些常見的內存泄漏案例:瀏覽器
大部分認爲閉包就是函數內部嵌套並return一個函數,我翻了翻幾本書中的描述:markdown
閉包涉及的範圍是比較廣了,如今看一個廣泛的例子再認識一下閉包:閉包
function fnOne(){
let test = new Array(1000).fill('www')
return function(){
console.log('hahaha')
}
}
let fn1Child = fnOne()
fn1Child()
複製代碼
這裏由於return的函數中存在函數fnOne中的test變量引用,test不會被回收,也就形成了內存泄漏。app
怎麼解決呢?就是在函數調用後,把外部的引用關係置空就行了:函數
function fnOne(){
let test = new Array(1000).fill('www')
return function(){
console.log(test)
return test
}
}
let fn1Child = fnOne();
fn1Child()
fn1Child = null;
複製代碼
減小使用閉包,不正當的使用閉包可能會形成內存泄漏。post
在JavaScript中,垃圾回收是自動執行的,可是對於全局變量,垃圾回收器很難判斷這些變量何時纔不被須要,因此全局變量不會被回收,這時候就產生了內存泄漏:測試
function fn(){
// 沒有聲明從而製造了隱式全局變量test1
test1 = new Array(1000).fill('isboyjc1')
// 函數內部this指向window,製造了隱式全局變量test2
this.test2 = new Array(1000).fill('isboyjc2')
}
fn()
複製代碼
let someResource = getData()
setInterval(() => {
const node = document.getElementById('Node')
if(node) {
node.innerHTML = JSON.stringify(someResource))
}
}, 1000)
複製代碼
代碼中,每隔一秒就把獲得的數據放入到node節點中,可是在setInterval
沒有結束以前,回調函數裏的變量以及回調函數自己都沒法被回收。這時候須要用到clearInterval
來清理這個定時器,才能回收someResource
。
setTiemout
也是一樣的道理,不須要時候,及時去清除。
在代碼中咱們會用到事件監聽器,在組件內掛載相關的函數,組件銷燬時候不主動清除時,其中的變量和函數會被認爲是須要的,就不會被回收,這些內部引用的變量存儲了大量數據,就會引發頁面佔用內存太高,形成內存泄漏。
不論是Vue仍是React,監聽者模式實現一些消息通訊是 很廣泛的,好比EventBus,當咱們實現了監聽者模式在組件內掛載相關的函數,組件銷燬時候不主動清除,就一樣不會進行回收。這時候咱們要在beforeDestroy
組件銷燬生命週期裏及時去清除。
最後就是咱們在聯調時候常見的console.log
了,咱們在瀏覽器控制檯能夠看到數據輸出,輸出對象的時候就也形成了內存泄漏。
差很少說完了常見的內存泄漏,下一篇就講一下怎麼排查定位代碼中是否存在內存泄漏
。