JavaScript的垃圾回收

JavaScript的垃圾回收

前段時間讀了一下<<JavaScript高級程序設(shè)計>>(書名很嚇人, 實際上作者寫得很好, 由淺入深), 了解了一下JavaScript的垃圾回收機制.

和Java一樣, JavaScript有自動垃圾回收機制.

JavaScript的垃圾回收機制很簡單:

找出不再使用的變量, 然后釋放掉其占用的內(nèi)存, 但是這個過程不是實時的, 因為開銷太大, 所以垃圾回收器會按照固定的時間周期性執(zhí)行.

變量生命周期

變量主要分為: 全局變量和局部變量.
全局變量的生命周期直至瀏覽器關(guān)閉頁面才會結(jié)束, 而局部變量只在函數(shù)執(zhí)行的過程中存在, 而在這個過程中會為局部變量在棧或堆上分配相應(yīng)的內(nèi)存空間, 以存儲它的值, 然后再在函數(shù)中使用這些變量, 直至函數(shù)結(jié)束(閉包中由于內(nèi)部函數(shù)的原因, 外部函數(shù)并不能算是結(jié)束了, 了解閉包可以看看JavaScript作用域鏈和閉包究竟是什么?)

一旦函數(shù)結(jié)束, 局部變量就沒有存在的必要了, 可以釋放它們占用的內(nèi)存.看似好像很簡單的工作, 為什么會有很大的開銷呢? 垃圾回收器需知道哪些變量有用, 哪些變量沒用, 對于不再有用的變量打上標(biāo)記, 以備將來回收. 用于標(biāo)記無用的策略很多, 常見的有兩種: 標(biāo)記清除和引用計數(shù).

標(biāo)記清除

這是JavaScript常見的垃圾回收方式, 當(dāng)變量進(jìn)入執(zhí)行環(huán)境時, 比如函數(shù)中聲明一個變量, 垃圾回收器將其標(biāo)記為"進(jìn)入環(huán)境", 當(dāng)變量離開環(huán)境的時候(函數(shù)執(zhí)行結(jié)束), 將其標(biāo)記為"離開環(huán)境". 至于怎么標(biāo)記有很多方法. 比如特殊位的反轉(zhuǎn), 維護(hù)一個列表等.

垃圾回收器會在運行的時候給存儲在內(nèi)存中的所有變量加上標(biāo)記, 然后去掉環(huán)境中的變量以及被環(huán)境變量所引用的變量(閉包), 在這些完成之后仍存在標(biāo)記的就是要刪除的變量, 因為環(huán)境中的變量已經(jīng)無法訪問到這些變量了, 然后垃圾回收器會清除這些標(biāo)記的變量所占的內(nèi)存空間.

大部份的瀏覽都是使用這種方式進(jìn)行垃圾回收, 區(qū)別在于如何標(biāo)記及垃圾回收間隔罷了.只有低版本的IE...

引用計數(shù)

在低版本的IE中經(jīng)常會出現(xiàn)內(nèi)存泄露, 很多時候是因為其采用引用計數(shù)方式進(jìn)行垃圾回收.

引用計數(shù)的策略是:

跟蹤記錄每個值被使用的次數(shù), 當(dāng)聲明一個變量并將一個引用類型賦值給該變量的時候, 這個值的引用次數(shù)
就加1, 如果該變量的值變成另一個, 則這個值的引用次數(shù)減1, 當(dāng)這個值的引用次數(shù)為1時, 說明沒有變量在使用, 這個值沒法被訪問了. 因此可以將其占用的內(nèi)存空間回收. 這樣垃圾回收器會在運行的時候清理掉引用次數(shù)為0的變量所占的內(nèi)存空間.

看起來不錯的方式, 為什么很少有瀏覽器采用, 還會帶來內(nèi)存泄露呢?
主要是因為這種方式?jīng)]法解決循環(huán)引用問題. 比如對象A有一個屬性指向?qū)ο驜, 而對象B也有一個屬性指向?qū)ο驛, 這樣的相互引用.

在IE中雖然JavaScript對象通過標(biāo)記清除的方式進(jìn)行垃圾回收, 但BOM與DOM對象卻是通過引用計數(shù)回收垃圾的,也就是說只要涉及BOM及DOM就很可能會出現(xiàn)循環(huán)引用的問題.如:

window.onload = function outFunction(){
    var obj = document.getElementById("element");
    obj.onclick = function innerFunction(){};
}

這段代碼看起來沒什么問題, 但是obj引用了document.getElementById("element"), 而document.getElementById("element")的onclick方法會引用外部環(huán)境中的變量, 自然也包括obj, 是不是很隱蔽?

解決辦法:
最簡單的辦法就是自己手工解除循環(huán)引用, 比如上面的例子:

window.onload = function outFunction(){
    var obj = document.getElementById("element");
    obj.onclick = function innerFunction(){};
    obj = null;
}

什么時候觸發(fā)垃圾回收

垃圾回收器周期運行, 如果分配的內(nèi)存非常多, 那么回收工作會很困難, 確定垃圾回收時間間隔變成了一個值得思考的問題. IE6的垃圾回收是根據(jù)內(nèi)存分配量運行的, 當(dāng)環(huán)境中存在256個變量, 4096個對象, 64K的字符串任意一種的情況下, 就會觸發(fā)垃圾回收器工作, 看起來很科學(xué), 不用按一段時間就調(diào)用一次, 但有時候會沒有必要, 這樣按需調(diào)用不是很好嗎? 但如果環(huán)境中就是有這么多變量一直存在, 現(xiàn)在腳本如此復(fù)雜, 很正常, 那么結(jié)果就是垃圾回收器一直在工作, 這樣瀏覽器就沒法玩了.

微軟在IE7中做了調(diào)整, 觸發(fā)條件不再是固定的, 而是動態(tài)修改的, 初始值和IE6相同, 如果垃圾回收器回收的內(nèi)存分配量低于程序占用內(nèi)存的15%, 說明大部分內(nèi)存不可被回收, 設(shè)的垃圾回收觸發(fā)條件過于敏感, 這時就把臨界條件*2, 如果回收的內(nèi)存高于85%, 說明大部分內(nèi)存該清理了, 這時把觸發(fā)條件重置, 這樣就使得垃圾回收工作變得智能很多.

同Java一樣, 我們可以手工調(diào)用垃圾回收程序, 但由于其消耗大量資源, 而且手工調(diào)用的不會比瀏覽器判斷的準(zhǔn)確, 所以不推薦手工調(diào)用垃圾回收.

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挎塌,一起剝皮案震驚了整個濱河市舷暮,隨后出現(xiàn)的幾起案子扒披,更是在濱河造成了極大的恐慌德召,老刑警劉巖受裹,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宿百,死亡現(xiàn)場離奇詭異壁公,居然都是意外死亡洲拇,警方通過查閱死者的電腦和手機奈揍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赋续,“玉大人男翰,你說我怎么就攤上這事∨β遥” “怎么了蛾绎?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鸦列。 經(jīng)常有香客問我租冠,道長,這世上最難降的妖魔是什么薯嗤? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任顽爹,我火速辦了婚禮,結(jié)果婚禮上骆姐,老公的妹妹穿的比我還像新娘镜粤。我一直安慰自己,他們只是感情好诲锹,可當(dāng)我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布繁仁。 她就那樣靜靜地躺著,像睡著了一般归园。 火紅的嫁衣襯著肌膚如雪黄虱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天庸诱,我揣著相機與錄音捻浦,去河邊找鬼晤揣。 笑死,一個胖子當(dāng)著我的面吹牛朱灿,可吹牛的內(nèi)容都是我干的昧识。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼盗扒,長吁一口氣:“原來是場噩夢啊……” “哼跪楞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起侣灶,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤甸祭,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后褥影,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體池户,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年凡怎,在試婚紗的時候發(fā)現(xiàn)自己被綠了校焦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡统倒,死狀恐怖寨典,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情檐薯,我是刑警寧澤凝赛,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站坛缕,受9級特大地震影響墓猎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赚楚,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一毙沾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宠页,春花似錦左胞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至俭嘁,卻和暖如春躺枕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工拐云, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留罢猪,地道東北人。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓叉瘩,卻偏偏與公主長得像膳帕,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子薇缅,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容