麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁(yè) > 編程 > JavaScript > 正文

JavaScript 垃圾回收機(jī)制分析

2019-11-20 21:54:28
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

在公司經(jīng)常會(huì)聽(tīng)到大牛們討論時(shí)說(shuō)道內(nèi)存泄露神馬的,每每都驚羨不已,最近精力主要用在了Web 開(kāi)發(fā)上,讀了一下《JavaScript高級(jí)程序設(shè)計(jì)》(書(shū)名很唬人,實(shí)際作者寫(xiě)的特別好,由淺入深)了解了一下JavaScript垃圾回收機(jī)制,對(duì)內(nèi)存泄露有了一定的認(rèn)識(shí)。

和C#、Java一樣JavaScript有自動(dòng)垃圾回收機(jī)制,也就是說(shuō)執(zhí)行環(huán)境會(huì)負(fù)責(zé)管理代碼執(zhí)行過(guò)程中使用的內(nèi)存,在開(kāi)發(fā)過(guò)程中就無(wú)需考慮內(nèi)存分配及無(wú)用內(nèi)存的回收問(wèn)題了。JavaScript垃圾回收的機(jī)制很簡(jiǎn)單:找出不再使用的變量,然后釋放掉其占用的內(nèi)存,但是這個(gè)過(guò)程不是時(shí)時(shí)的,因?yàn)槠溟_(kāi)銷(xiāo)比較大,所以垃圾回收器會(huì)按照固定的時(shí)間間隔周期性的執(zhí)行。

變量生命周期

有同學(xué)看了上面就會(huì)問(wèn)了,什么叫不再使用的變量?不再使用的變量也就是生命周期結(jié)束的變量,當(dāng)然只可能是局部變量,全局變量的生命周期直至瀏覽器卸載頁(yè)面才會(huì)結(jié)束。局部變量只在函數(shù)的執(zhí)行過(guò)程中存在,而在這個(gè)過(guò)程中會(huì)為局部變量在棧或堆上分配相應(yīng)的空間,以存儲(chǔ)它們的值,然后再函數(shù)中使用這些變量,直至函數(shù)結(jié)束(閉包中由于內(nèi)部函數(shù)的原因,外部函數(shù)并不能算是結(jié)束,了解閉包可以看看 JavaScript作用域鏈,JavaScript 閉包究竟是什么)。

一旦函數(shù)結(jié)束,局部變量就沒(méi)有存在必要了,可以釋放它們占用的內(nèi)存。貓和很簡(jiǎn)單的工作,為什么會(huì)有很大開(kāi)銷(xiāo)呢?這僅僅是垃圾回收的冰山一角,就像剛剛提到的閉包,貌似函數(shù)結(jié)束了,其實(shí)還沒(méi)有,垃圾回收器必須那個(gè)變量游泳,那個(gè)變量沒(méi)用,對(duì)于不再有用的變量打上標(biāo)記,以備將來(lái)回收。用于標(biāo)記無(wú)用的策略有很多,常見(jiàn)的有兩種方式

標(biāo)記清除(mark and sweep)

這是JavaScript最常見(jiàn)的垃圾回收方式,當(dāng)變量進(jìn)入執(zhí)行環(huán)境的時(shí)候,比如函數(shù)中聲明一個(gè)變量,垃圾回收器將其標(biāo)記為“進(jìn)入環(huán)境”,當(dāng)變量離開(kāi)環(huán)境的時(shí)候(函數(shù)執(zhí)行結(jié)束)將其標(biāo)記為“離開(kāi)環(huán)境”。至于怎么標(biāo)記有很多種方式,比如特殊位的反轉(zhuǎn)、維護(hù)一個(gè)列表等,這些并不重要,重要的是使用什么策略,原則上講不能夠釋放進(jìn)入環(huán)境的變量所占的內(nèi)存,它們隨時(shí)可能會(huì)被調(diào)用的到。

垃圾回收器會(huì)在運(yùn)行的時(shí)候給存儲(chǔ)在內(nèi)存中的所有變量加上標(biāo)記,然后去掉環(huán)境中的變量以及被環(huán)境中變量所引用的變量(閉包),在這些完成之后仍存在標(biāo)記的就是要?jiǎng)h除的變量了,因?yàn)榄h(huán)境中的變量已經(jīng)無(wú)法訪問(wèn)到這些變量了,然后垃圾回收器相會(huì)這些帶有標(biāo)記的變量機(jī)器所占空間。

大部分瀏覽器都是使用這種方式進(jìn)行垃圾回收,區(qū)別在于如何標(biāo)記及垃圾回收間隔而已,只有低版本IE,不出所料,又是IE。。。

引用計(jì)數(shù)(reference counting)

在低版本IE中經(jīng)常會(huì)出現(xiàn)內(nèi)存泄露,很多時(shí)候就是因?yàn)槠洳捎靡糜?jì)數(shù)方式進(jìn)行垃圾回收。引用計(jì)數(shù)的策略是跟蹤記錄每個(gè)值被使用的次數(shù),當(dāng)聲明了一個(gè)變量并將一個(gè)引用類(lèi)型賦值給該變量的時(shí)候這個(gè)值的引用次數(shù)就加1,如果該變量的值變成了另外一個(gè),則這個(gè)值得引用次數(shù)減1,當(dāng)這個(gè)值的引用次數(shù)變?yōu)?的時(shí)候,說(shuō)明沒(méi)有變量在使用,這個(gè)值沒(méi)法被訪問(wèn)了,因此可以將其占用的空間回收,這樣垃圾回收器會(huì)在運(yùn)行的時(shí)候清理掉引用次數(shù)為0的值占用的空間。

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

復(fù)制代碼 代碼如下:

function test(){
            var a={};
            var b={};
            a.prop=b;
            b.prop=a;
        }

這樣a和b的引用次數(shù)都是2,即使在test()執(zhí)行完成后,兩個(gè)對(duì)象都已經(jīng)離開(kāi)環(huán)境,在標(biāo)記清除的策略下是沒(méi)有問(wèn)題的,離開(kāi)環(huán)境的就被清除,但是在引用計(jì)數(shù)策略下不行,因?yàn)檫@兩個(gè)對(duì)象的引用次數(shù)仍然是2,不會(huì)變成0,所以其占用空間不會(huì)被清理,如果這個(gè)函數(shù)被多次調(diào)用,這樣就會(huì)不斷地有空間不會(huì)被回收,造成內(nèi)存泄露。

在IE中雖然JavaScript對(duì)象通過(guò)標(biāo)記清除的方式進(jìn)行垃圾回收,但BOM與DOM對(duì)象卻是通過(guò)引用計(jì)數(shù)回收垃圾的,也就是說(shuō)只要涉及BOM及DOM就會(huì)出現(xiàn)循環(huán)引用問(wèn)題。看上面的例子,有同學(xué)回覺(jué)得太弱了,誰(shuí)會(huì)做這樣無(wú)聊的事情,其實(shí)我們是不是就在做

復(fù)制代碼 代碼如下:

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

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

解決辦法

最簡(jiǎn)單的方式就是自己手工解除循環(huán)引用,比如剛才的函數(shù)可以這樣

復(fù)制代碼 代碼如下:

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

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

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

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

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

發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 久久嗨 | 视频一区二区不卡 | 人成免费a级毛片 | 成人福利在线视频 | 欧美成人免费tv在线播放 | 巨根插入| lutube成人福利在线观看污 | 蜜桃av鲁一鲁一鲁一鲁 | 青青操精品 | 亚洲一级片免费观看 | 欧美成人三级视频 | 久久久久一区二区三区 | 一本一本久久a久久精品综合小说 | 亚洲午夜在线视频 | 欧美日本免费一区二区三区 | 欧美va亚洲| 久久精品在线免费观看 | 日韩黄色影视 | 爽爽淫人网 | 欧美中文字幕一区二区三区亚洲 | 国产69精品久久久久99尤 | 污污的视频在线观看 | 国产亚洲综合一区二区 | 99国产精品国产免费观看 | 国产片91 | 国产成人免费精品 | 精品久久久久久久久亚洲 | 久久蜜桃精品一区二区三区综合网 | 欧美成年人在线视频 | 日本黄色a视频 | www.7777在线 | 色天天综合网 | 亚洲一区二区免费 | 久久伊人国产精品 | 72pao成人国产永久免费视频 | 午夜视频久久 | sesee99| 国产精品一区二区三区在线 | 欧美成人久久 | av不卡毛片 | 久久精片 |