JavaScript 垃圾回收與內(nèi)存泄漏
瀏覽器的垃圾回收機(jī)制?
垃圾回收的概念:JS代碼運行時,需要分配內(nèi)存空間來儲存變量和值。當(dāng)變量不再參與運行時,就需要系統(tǒng)收回被占用的內(nèi)存空間。
垃圾回收機(jī)制:
-
JS具有自動垃圾回收機(jī)制,會定期對那些不再使用的變量、對象所占用的內(nèi)存進(jìn)行釋放;
原理就是找到不再使用的變量,釋放掉其所占用的內(nèi)存。 -
JS中存在兩種變量,局部變量和全局變量。
全局變量的生命周期會持續(xù)到頁面卸載;
而局部變量聲明在函數(shù)中,它的生命周期從執(zhí)行函數(shù)開始,直到函數(shù)執(zhí)行結(jié)束,在這個過程中,局部變量會在堆或者棧中存儲它們的值,當(dāng)函數(shù)執(zhí)行結(jié)束后,這些局部變量不再被使用,它們所占用的空間就會被釋放。 -
當(dāng)局部變量被外部函數(shù)使用時,其中一種情況就是閉包,在函數(shù)執(zhí)行結(jié)束后,函數(shù)外部的變量依然指向函數(shù)內(nèi)部的局部變量,此時局部變量依然在被使用,所以不會被回收。
垃圾回收的方式:瀏覽器通常使用的垃圾回收方式有2種:標(biāo)記清除、引用計數(shù)。
-
標(biāo)記清除:
- 標(biāo)記清除是瀏覽器常見的垃圾回收方式。當(dāng)變量進(jìn)入執(zhí)行環(huán)境時,就標(biāo)記這個變量“進(jìn)入環(huán)境”,被標(biāo)記為“進(jìn)入環(huán)境”的變量是不能被回收的,因為他們正在被使用。當(dāng)變量離開環(huán)境時,就會被標(biāo)記為“離開環(huán)境”,被標(biāo)記為“離開環(huán)境”的變量會被內(nèi)存釋放。
- 垃圾收集器在運行的時候會給存儲在內(nèi)存中的所有變量都加上標(biāo)記。
然后,它會去掉環(huán)境中的變量以及被環(huán)境中的變量引用的標(biāo)記。
而在此之后再被加上標(biāo)記的變量將被視為準(zhǔn)備刪除的變量,原因是環(huán)境中的變量已經(jīng)無法訪問到這些變量了。
最后,垃圾收集器完成內(nèi)存清除工作,銷毀那些帶標(biāo)記的值,并回收他們所占用的內(nèi)存空間。
-
引用計數(shù)(這個用的相對較少):
- 引用計數(shù)就是跟蹤記錄每個值被引用的次數(shù)。
當(dāng)聲明了一個變量并將一個引用類型賦值給該變量時,則這個值的引用次數(shù)就是1。
相反,如果包含對這個值引用的變量又取得了另外一個值,則這個值的引用次數(shù)就減1。
當(dāng)這個引用次數(shù)變?yōu)?時,說明這個變量已經(jīng)沒有價值,因此,在垃機(jī)回收期下次再運行時,這個變量所占有的內(nèi)存空間就會被釋放出來。 - 這種方法會引起循環(huán)引用的問題:
例如: obj1和obj2通過屬性進(jìn)行相互引用,兩個對象的引用次數(shù)都是2。
當(dāng)使用循環(huán)計數(shù)時,由于函數(shù)執(zhí)行完后,兩個對象都離開作用域,函數(shù)執(zhí)行結(jié)束,obj1和obj2還將會繼續(xù)存在,因此它們的引用次數(shù)永遠(yuǎn)不會是0,就會引起循環(huán)引用。
- 引用計數(shù)就是跟蹤記錄每個值被引用的次數(shù)。
點擊查看代碼
function fun() {
let obj1 = {};
let obj2 = {};
obj1.a = obj2; // obj1 引用 obj2
obj2.a = obj1; // obj2 引用 obj1
}
這種情況下,就要手動釋放變量占用的內(nèi)存:
obj1.a = null
obj2.a = null
減少垃圾回收:雖然瀏覽器可以進(jìn)行垃圾自動回收,但是當(dāng)代碼比較復(fù)雜時,垃圾回收所帶來的代價比較大,所以應(yīng)該盡量減少垃圾回收。
- 對數(shù)組進(jìn)行優(yōu)化:
在清空一個數(shù)組時,最簡單的方法就是給其賦值為[ ],但是與此同時會創(chuàng)建一個新的空對象,可以將數(shù)組的長度設(shè)置為0,以此來達(dá)到清空數(shù)組的目的。 - 對object進(jìn)行優(yōu)化:
對象盡量復(fù)用,對于不再使用的對象,就將其設(shè)置為null,盡快被回收。 - 對函數(shù)進(jìn)行優(yōu)化:
在循環(huán)中的函數(shù)表達(dá)式,如果可以復(fù)用,盡量放在函數(shù)的外面。
哪些情況會導(dǎo)致內(nèi)存泄漏?
- 意外的全局變量:
由于使用未聲明的變量,而意外的創(chuàng)建了一個全局變量,而使這個變量一直留在內(nèi)存中無法被回收。 - 被遺忘的計時器或回調(diào)函數(shù):
設(shè)置了 setInterval 定時器,而忘記取消它,如果循環(huán)函數(shù)有對外部變量的引用的話,那么這個變量會被一直留在內(nèi)存中,而無法被回收。 - 脫離 DOM 的引用:
獲取一個 DOM 元素的引用,而后面這個元素被刪除,由于一直保留了對這個元素的引用,所以它也無法被回收。 - 閉包:
不合理的使用閉包,從而導(dǎo)致某些變量一直被留在內(nèi)存當(dāng)中。

浙公網(wǎng)安備 33010602011771號