JavaScript 是一種動(dòng)態(tài)的、弱類型的腳本語言。在代碼運(yùn)行時(shí),會(huì)為變量、函數(shù)等分配內(nèi)存空間,垃圾收集機(jī)制便是用于回收這些被占用的內(nèi)存。垃圾收集器會(huì)定期檢查內(nèi)存的使用情況,找出不再使用的值,回收它們占用的內(nèi)存。
JavaScript 語言的垃圾收集機(jī)制主要有兩種:標(biāo)記清除(Mark-and-sweep)和引用計(jì)數(shù)(Reference counting)。
//標(biāo)記清除
function foo() {
let a = 1;
let b = 2;
return a + b;
}
foo(); //執(zhí)行后,a 和 b 這兩個(gè)變量占用的內(nèi)存會(huì)被標(biāo)記為不再使用
//引用計(jì)數(shù)
let a = {name: 'Tom'};
let b = a; //保存了 a 對(duì)象的引用
a = null; //斷開 a 對(duì)象的引用
//此時(shí) b 對(duì)象還存在,引用計(jì)數(shù)器不為 0,b 對(duì)象所占用的內(nèi)存仍然沒有被回收
標(biāo)記清除算法會(huì)將代碼中所有被使用過的變量和對(duì)象標(biāo)記起來,在標(biāo)記完成后,沒有被標(biāo)記的則被認(rèn)為是無用的數(shù)據(jù)。引用計(jì)數(shù)算法則是統(tǒng)計(jì)訪問被使用到的次數(shù),成為 0 的變量就被認(rèn)為不再被使用,可以被回收。
JavaScript 垃圾收集機(jī)制是自動(dòng)的,不需要顯式地釋放內(nèi)存,但是對(duì)于大型項(xiàng)目,內(nèi)存泄漏的情況還是較為常見。比如,代碼中的函數(shù)閉包、定時(shí)器或事件綁定都可能引起內(nèi)存泄漏。
// 針對(duì)函數(shù)閉包導(dǎo)致的內(nèi)存泄漏
function f() {
let arr = new Array(1000000);
let obj = {a: 1};
return function() {
// ...
}
}
let fn = f(); //執(zhí)行 f 函數(shù)后,會(huì)創(chuàng)建一個(gè)閉包,并且占用大量數(shù)組和對(duì)象的內(nèi)存
fn = null; //但是由于 fn 還在引用著閉包,就算該閉包無法被訪問了,但是占用的大量?jī)?nèi)存無法得到回收
避免內(nèi)存泄漏的方式有很多。一種比較重要的方式是,盡量減少不必要的變量和對(duì)象的創(chuàng)建,以減少其占用的內(nèi)存。
JavaScript 的垃圾收集機(jī)制是一項(xiàng)非常重要的功能,它為 JavaScript 的應(yīng)用場(chǎng)景提供了無限可能。在編寫 JavaScript 代碼時(shí),應(yīng)該注意避免內(nèi)存泄漏,合理利用垃圾收集器回收無用的內(nèi)存空間,這樣才能讓 JavaScript 代碼高效地開發(fā)和運(yùn)行。