2018-10-13

淺談瀏覽器的垃圾回收機制和內(nèi)存泄露

JavaScript使用垃圾回收機制來自動管理內(nèi)存挂疆。

JS的回收機制分兩種:1.標記清除 2.引用計數(shù)仔雷。各大瀏覽器常用的是前者眨补。

比如,Chrome瀏覽器限制的所能使用的內(nèi)存極限(64位為1.4GB蒜哀,32位為1.0GB),這就意味著瀏覽器將無法直接操作一些大內(nèi)存對象吏砂。

標記清除:

定義和用法:當(dāng)變量進入環(huán)境時撵儿,將變量標記"進入環(huán)境",當(dāng)變量離開環(huán)境時狐血,標記為:"離開環(huán)境"淀歇。某一個時刻,垃圾回收器會過濾掉環(huán)境中的變量氛雪,以及被環(huán)境變量引用的變量房匆,剩下的就是被視為準備回收的變量。

到目前為止,IE浴鸿、Firefox井氢、Opera、Chrome岳链、Safari的js實現(xiàn)使用的都是標記清除的垃圾回收策略或類似的策略花竞,只不過垃圾收集的時間間隔互不相同。

  工作流程:
  1. 垃圾回收器掸哑,在運行的時候會給存儲在內(nèi)存中的所有變量都加上標記约急。

  2. 去掉環(huán)境中的變量以及被環(huán)境中的變量引用的變量的標記。

  3. 再被加上標記的會被視為準備刪除的變量苗分。

  4. 垃圾回收器完成內(nèi)存清除工作厌蔽,銷毀那些帶標記的值并回收他們所占用的內(nèi)存空間。

引用計數(shù):

定義和用法:引用計數(shù)是跟蹤記錄每個值被引用的次數(shù)摔癣。

基本原理:就是變量的引用次數(shù)奴饮,被引用一次則加1,當(dāng)這個引用計數(shù)為0時择浊,被視為準備回收的對象戴卜。

   工作流程:
  1. 聲明了一個變量并將一個引用類型的值賦值給這個變量,這個引用類型值的引用次數(shù)就是1琢岩。

  2. 同一個值又被賦值給另一個變量投剥,這個引用類型值的引用次數(shù)加1.

  3. 當(dāng)包含這個引用類型值的變量又被賦值成另一個值了,那么這個引用類型值的引用次數(shù)減1.

  4. 當(dāng)引用次數(shù)變成0時担孔,說明沒辦法訪問這個值了江锨。

  5. 當(dāng)垃圾收集器下一次運行時,它就會釋放引用次數(shù)是0的值所占的內(nèi)存攒磨。

但是循環(huán)引用的時候就會釋放不掉內(nèi)存泳桦。循環(huán)引用就是對象A中包含另一個指向?qū)ο驜的指針,B中也包含一個指向A的引用娩缰。

因為IE中的BOM灸撰、DOM的實現(xiàn)使用了COM,而COM對象使用的垃圾收集機制是引用計數(shù)策略拼坎。所以會存在循環(huán)引用的問題浮毯。

解決:手工斷開js對象和DOM之間的鏈接。賦值為null泰鸡。IE9把DOM和BOM轉(zhuǎn)換成真正的JS對象了债蓝,所以避免了這個問題。

內(nèi)存管理

1盛龄、什么時候觸發(fā)垃圾回收饰迹?

垃圾回收器周期性運行芳誓,如果分配的內(nèi)存非常多,那么回收工作也會很艱巨啊鸭,確定垃圾回收時間間隔就變成了一個值得思考的問題锹淌。

IE6的垃圾回收是根據(jù)內(nèi)存分配量運行的,當(dāng)環(huán)境中的變量赠制,對象赂摆,字符串達到一定數(shù)量時觸發(fā)垃圾回收。垃圾回收器一直處于工作狀態(tài)钟些,嚴重影響瀏覽器性能烟号。

IE7中,垃圾回收器會根據(jù)內(nèi)存分配量與程序占用內(nèi)存的比例進行動態(tài)調(diào)整政恍,開始回收工作汪拥。

2、合理的GC方案:(1)抚垃、遍歷所有可訪問的對象; (2)喷楣、回收已不可訪問的對象趟大。

3鹤树、GC缺陷:(1)、停止響應(yīng)其他操作逊朽;

4罕伯、GC優(yōu)化策略:(1)、分代回收(Generation GC);(2)叽讳、增量GC

開發(fā)過程中遇到的內(nèi)存泄露情況

1追他、定義和用法:

內(nèi)存泄露是指一塊被分配的內(nèi)存既不能使用,又不能回收岛蚤,直到瀏覽器進程結(jié)束邑狸。C#和Java等語言采用了自動垃圾回收方法管理內(nèi)存,幾乎不會發(fā)生內(nèi)存泄露涤妒。我們知道单雾,瀏覽器中也是采用自動垃圾回收方法管理內(nèi)存,但由于瀏覽器垃圾回收方法有bug她紫,會產(chǎn)生內(nèi)存泄露硅堆。

由于每次的垃圾回收開銷都相對較大,并且由于機制的一些不完善的地方贿讹,可能會導(dǎo)致內(nèi)存泄露渐逃。我們可以利用一些方法減少垃圾回收,并且盡量避免循環(huán)引用的問題民褂。

例如茄菊,在對象結(jié)束使用后 疯潭,令obj = null。這樣利于解除循環(huán)引用面殖,使得無用變量及時被回收袁勺。

再如,js中開辟空間的操作有new(), [ ], { }, function (){..}畜普。在創(chuàng)建新對象的時候要盡量考慮增大對象的復(fù)用性期丰。

2、內(nèi)存泄露的幾種情況:

雖然有垃圾回收機制吃挑,但是钝荡,我們編寫代碼操作不當(dāng)還是會造成內(nèi)存泄漏。

  1. 意外的全局變量引起的內(nèi)存泄漏舶衬。

原因:全局變量埠通,不會被回收。

解決:使用嚴格模式避免逛犹。

  1. 閉包引起的內(nèi)存泄漏

原因:閉包可以維持函數(shù)內(nèi)局部變量端辱,使其得不到釋放。

解決:將事件處理函數(shù)定義在外部虽画,解除閉包,或者在定義事件處理函數(shù)的外部函數(shù)中舞蔽,刪除對dom的引用。

  1. 沒有清理的DOM元素引用

原因:雖然別的地方刪除了码撰,但是對象中還存在對dom的引用

解決:手動刪除渗柿。

  1. 被遺忘的定時器或者回調(diào)

原因:定時器中有dom的引用,即使dom刪除了脖岛,但是定時器還在朵栖,所以內(nèi)存中還是有這個dom。

解決:手動刪除定時器和dom柴梆。

  1. 子元素存在引用引起的內(nèi)存泄漏

原因:div中的ul li 得到這個div陨溅,會間接引用某個得到的li,那么此時因為div間接引用li绍在,即使li被清空门扇,也還是在內(nèi)存中,并且只要li不被刪除揣苏,他的父元素都不會被刪除悯嗓。

解決:手動刪除清空。

內(nèi)存泄露解決舉例:

(1)卸察、當(dāng)頁面中元素被移除或替換時脯厨,若元素綁定的事件仍沒被移除,在IE中不會作出恰當(dāng)處理坑质,此時要先手工移除事件合武,不然會存在內(nèi)存泄露临梗。

實例如下:

<div id="myDiv">
    <input type="button" value="Click me" id="myBtn">
</div>
<script type="text/javascript">
    var btn = document.getElementById("myBtn");
    btn.onclick = function(){
        document.getElementById("myDiv").innerHTML = "Processing...";
    }
</script>
<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; 
overflow-wrap: break-word; font-family: &quot;Courier New&quot;
 !important; font-size: 12px !important;"><div id="myDiv">
    <input type="button" value="Click me" id="myBtn">
</div>
<script type="text/javascript">
    var btn = document.getElementById("myBtn");
    btn.onclick = function(){
        document.getElementById("myDiv").innerHTML = "Processing...";
    }
</script></pre>

解決方法如下:

 <div id="myDiv">
    <input type="button" value="Click me" id="myBtn">
</div>
<script type="text/javascript">
    var btn = document.getElementById("myBtn");
    btn.onclick = function(){
    btn.onclick = null;
        document.getElementById("myDiv").innerHTML = "Processing...";
    }
</script>

(2)、由于是函數(shù)內(nèi)定義函數(shù)稼跳,并且內(nèi)部函數(shù)--事件回調(diào)的引用外暴了盟庞,形成了閉包。閉包可以維持函數(shù)內(nèi)局部變量汤善,使其得不到釋放什猖。

實例如下:

function bindEvent(){
    var obj=document.createElement("XXX");
    obj.onclick=function(){
        //Even if it's a empty function
    }
}

解決方法如下:

function bindEvent(){
    var obj=document.createElement("XXX");
    obj.onclick=function(){
         //Even if it's a empty function
    }
    obj=null;
}

參考博文:

1.【面試題——js垃圾回收機制和引起內(nèi)存泄漏的操作】https://blog.csdn.net/yingzizizizizizzz/article/details/77333996

2.【2018最新Web前端經(jīng)典面試試題及答案】https://blog.csdn.net/wdlhao/article/details/79079660

3.【淺談Chrome V8引擎中的垃圾回收機制https://www.cnblogs.com/liangdaye/p/4654734.html


作者:龍波帝國------------------->打造我的IT帝國

歡迎交流,在下扣號:724711690红淡,請備注:前端技術(shù)交流

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末不狮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子在旱,更是在濱河造成了極大的恐慌摇零,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件桶蝎,死亡現(xiàn)場離奇詭異驻仅,居然都是意外死亡,警方通過查閱死者的電腦和手機登渣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門噪服,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人绍豁,你說我怎么就攤上這事芯咧。” “怎么了竹揍?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長邪铲。 經(jīng)常有香客問我芬位,道長,這世上最難降的妖魔是什么带到? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任昧碉,我火速辦了婚禮,結(jié)果婚禮上揽惹,老公的妹妹穿的比我還像新娘被饿。我一直安慰自己,他們只是感情好搪搏,可當(dāng)我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布狭握。 她就那樣靜靜地躺著,像睡著了一般疯溺。 火紅的嫁衣襯著肌膚如雪论颅。 梳的紋絲不亂的頭發(fā)上哎垦,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天,我揣著相機與錄音恃疯,去河邊找鬼漏设。 笑死,一個胖子當(dāng)著我的面吹牛今妄,可吹牛的內(nèi)容都是我干的郑口。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼盾鳞,長吁一口氣:“原來是場噩夢啊……” “哼潘酗!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起雁仲,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤仔夺,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后攒砖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體缸兔,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年吹艇,在試婚紗的時候發(fā)現(xiàn)自己被綠了惰蜜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡受神,死狀恐怖抛猖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鼻听,我是刑警寧澤财著,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布,位于F島的核電站撑碴,受9級特大地震影響撑教,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜醉拓,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一伟姐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧亿卤,春花似錦愤兵、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至傍念,卻和暖如春矫夷,著一層夾襖步出監(jiān)牢的瞬間葛闷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工双藕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留淑趾,地道東北人。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓忧陪,卻偏偏與公主長得像扣泊,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子嘶摊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,724評論 2 351