淺談瀏覽器的垃圾回收機制和內(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)使用的都是標記清除的垃圾回收策略或類似的策略花竞,只不過垃圾收集的時間間隔互不相同。
工作流程:
垃圾回收器掸哑,在運行的時候會給存儲在內(nèi)存中的所有變量都加上標記约急。
去掉環(huán)境中的變量以及被環(huán)境中的變量引用的變量的標記。
再被加上標記的會被視為準備刪除的變量苗分。
垃圾回收器完成內(nèi)存清除工作厌蔽,銷毀那些帶標記的值并回收他們所占用的內(nèi)存空間。
引用計數(shù):
定義和用法:引用計數(shù)是跟蹤記錄每個值被引用的次數(shù)摔癣。
基本原理:就是變量的引用次數(shù)奴饮,被引用一次則加1,當(dāng)這個引用計數(shù)為0時择浊,被視為準備回收的對象戴卜。
工作流程:
聲明了一個變量并將一個引用類型的值賦值給這個變量,這個引用類型值的引用次數(shù)就是1琢岩。
同一個值又被賦值給另一個變量投剥,這個引用類型值的引用次數(shù)加1.
當(dāng)包含這個引用類型值的變量又被賦值成另一個值了,那么這個引用類型值的引用次數(shù)減1.
當(dāng)引用次數(shù)變成0時担孔,說明沒辦法訪問這個值了江锨。
當(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)存泄漏。
- 意外的全局變量引起的內(nèi)存泄漏舶衬。
原因:全局變量埠通,不會被回收。
解決:使用嚴格模式避免逛犹。
- 閉包引起的內(nèi)存泄漏
原因:閉包可以維持函數(shù)內(nèi)局部變量端辱,使其得不到釋放。
解決:將事件處理函數(shù)定義在外部虽画,解除閉包,或者在定義事件處理函數(shù)的外部函數(shù)中舞蔽,刪除對dom的引用。
- 沒有清理的DOM元素引用
原因:雖然別的地方刪除了码撰,但是對象中還存在對dom的引用
解決:手動刪除渗柿。
- 被遺忘的定時器或者回調(diào)
原因:定時器中有dom的引用,即使dom刪除了脖岛,但是定時器還在朵栖,所以內(nèi)存中還是有這個dom。
解決:手動刪除定時器和dom柴梆。
- 子元素存在引用引起的內(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: "Courier New"
!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ù)交流