引言:對于 C 語言這般的低級語言俘侠,一般可以通過比如 malloc() 和 free()可以在內(nèi)存中釋放我們定義的變量。但是JavaScript的垃圾回收是自動進行的,那么js在何時回收變量呢恒序?
首先來看一下內(nèi)存的生命周期:
- 分配你所需要的內(nèi)存
- 使用分配到的內(nèi)存(讀三圆、寫)
- 不需要時將其釋放\歸還
所以,我們只要知道js引擎怎么判斷內(nèi)存變量不再需要污呼,就知道js是在什么時候回收內(nèi)存變量了裕坊。
我們先來說一種古老的垃圾回收機制:
引用計數(shù)垃圾收集
這是最簡單的垃圾收集算法。此算法把“對象是否不再需要”簡化定義為“對象有沒有其他對象引用到它”燕酷。如果沒有引用指向該對象(零引用)籍凝,對象將被垃圾回收機制回收周瞎。
我們看一段代碼來分析:
// 兩個對象被創(chuàng)建,一個作為另一個的屬性被引用饵蒂,另一個被分配給變量o
// 很顯然声诸,沒有一個可以被垃圾收集
var o = {
a: {
b:2
}
};
// o2變量是第二個對“這個對象”的引用
var o2 = o;
// 現(xiàn)在,“這個對象”的原始引用o被o2替換了
o = 1;
// 引用“這個對象”的a屬性
// 現(xiàn)在退盯,“這個對象”有兩個引用了彼乌,一個是o2,一個是oa
var oa = o2.a;
// 最初的對象現(xiàn)在已經(jīng)是零引用了
// 他可以被垃圾回收了
// 然而它的屬性a的對象還在被oa引用渊迁,所以還不能回收
o2 = "yo";
oa = null;
// a屬性的那個對象現(xiàn)在也是零引用了
// 它可以被垃圾回收了
引用計數(shù)垃圾收集有一個很大的缺陷:無法處理循環(huán)引用
比如慰照,無法處理下列代碼:
function f(){
var o = {};
var o2 = {};
// o 引用 o2
o.a = o2;
// o2 引用 o
o2.a = o;
}
f();
其實,引用計數(shù)垃圾收集 是古老的IE 6, 7 采用的垃圾手機機制琉朽,去他喵的IE6毒租,7
接下來我們介紹一個更現(xiàn)代化的垃圾收集機制:
標記-清除垃圾收集
這個算法把“對象是否不再需要”簡化定義為“對象是否可以獲得”。
這個算法假定設(shè)置一個叫做根(root)的對象(在Javascript里箱叁,根是全局對象)墅垮。定期的,垃圾回收器將從根開始耕漱,找所有從根開始引用的對象算色,然后找這些對象引用的對象……從根開始,垃圾回收器將找到所有可以獲得的對象和所有不能獲得的對象孤个。
這個算法比前一個要好剃允,因為“有零引用的對象”總是不可獲得的,但是相反卻不一定齐鲤。怎么理解呢斥废?比如這段引用計數(shù)沒法回收的代碼:
function f(){
var o = {};
var o2 = {};
// o 引用 o2
o.a = o2;
// o2 引用 o
o2.a = o;
}
f();
// 定期從window對象開始,o和o2不可獲得给郊,回收
從2012年起牡肉,所有現(xiàn)代瀏覽器都使用了標記-清除垃圾回收算法。所有對JavaScript垃圾回收算法的改進都是基于標記-清除算法的改進淆九,并沒有改進標記-清除算法本身和它對“對象是否不再需要”的簡化定義统锤。