js引起內(nèi)存泄露的幾種情況分析
內(nèi)存泄露是指一塊被分配的內(nèi)存既不能使用,又不能回收,直到瀏覽器進程結(jié)束。
在C++中,因為是手動管理內(nèi)存,內(nèi)存泄露是經(jīng)常出現(xiàn)的事情。
而現(xiàn)在流行的C#和Java等語言采用了自動垃圾回收方法管理內(nèi)存,正常使用的情況下幾乎不會發(fā)生內(nèi)存泄露。
瀏覽器中也是采用自動垃圾回收方法管理內(nèi)存,但由于瀏覽器垃圾回收方法有bug,會產(chǎn)生內(nèi)存泄露。
內(nèi)存泄露引起方式一:
當頁面中元素被移除或替換時,若元素綁定的事件仍沒被移除,在低版本IE中不會作出恰當處理,此時要先手工移除事件,不然會存在內(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 = "實例";
}
</script>
<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 = "實例";
}
</script>
或者采用事件委托:
<div id="myDiv">
<input type="button" value="Click me" id="myBtn">
</div>
<script type="text/javascript">
document.onclick = function(event){
event = event || window.event;
if(event.target.id == "myBtn"){
document.getElementById("myDiv").innerHTML = "實例";
}
}
內(nèi)存泄露方式二:
var a=document.getElementById("#xx");
var b=document.getElementById("#xxx");
a.r=b;
b.r=a;
對于純粹的ECMAScript對象而言,只要沒有其他對象引用對象 a、b,也就是說它們只是相互之間的引用,那么仍然會被垃圾收集系統(tǒng)識別并處理。但是在低版本的 Inter Explorer 中,如果循環(huán)引用中的任何對象是 DOM 節(jié)點或者 ActiveX 對象,垃圾收集系統(tǒng)則不會發(fā)現(xiàn)它們之間的循環(huán)關(guān)系與系統(tǒng)中的其他對象是隔離的并釋放它們。最終它們將被保留在內(nèi)存中,直到瀏覽器關(guān)閉。
內(nèi)存泄露方式三:
var elem = document.getElementById('test');
elem.addEventListener('click', function() {
alert('You clicked ' + elem.tagName);
});
這段代碼把一個匿名函數(shù)注冊為一個DOM結(jié)點的click事件處理函數(shù),函數(shù)內(nèi)引用了一個DOM對象elem,就形成了閉包。
這就會產(chǎn)生一個循環(huán)引用,即:DOM->閉包->DOM->閉包...DOM對象在閉包釋放之前不會被釋放;
而閉包作為DOM對象的事件處理函數(shù)存在,所以在DOM對象釋放前閉包不會釋放,即使DOM對象在DOM tree中刪除,由于這個循環(huán)引用的存在,DOM對象和閉包都不會被釋放。可以用下面的方法可以避免這種內(nèi)存泄露 :
var elem = document.getElementById('test');
elem.addEventListener('click', function() {
alert('You clicked ' + this.tagName); // 不再直接引用elem變量
});
內(nèi)存泄露方式四:
function bindEvent() {
var obj=document.createElement("XXX");
obj.onclick=function(){
//Even if it's a empty function
}
}
閉包非常容易構(gòu)成循環(huán)引用。如果一個構(gòu)成閉包的函數(shù)對象被指定給,比如一個 DOM 節(jié)點的事件處理器,而對該節(jié)點的引用又被指定給函數(shù)對象作用域中的一個活動(或可變)對象,那么就存在一個循環(huán)引用。 [
DOM_Node.onevent -<function_object.[[scope]] -<scope_chain -<Activation_object.nodeRef -<DOM_Node。
形成這樣一個循環(huán)引用是輕而易舉的,而且稍微瀏覽一下包含類似循環(huán)引用代碼的網(wǎng)站(通常會出現(xiàn)在網(wǎng)站的每個頁面中),就會消耗大量(甚至全部)系統(tǒng)內(nèi)存。 解決之道,將事件處理函數(shù)定義在外部,解除閉包 :
function bindEvent(){
var obj=document.createElement("XXX");
obj.onclick=onclickHandler;
}
function onclickHandler(){
//do something
}
或者在定義事件處理函數(shù)的外部函數(shù)中,刪除對dom的引用(題外,《JavaScript權(quán)威指南》中介紹過,閉包中,作用域中沒用的屬性可以刪除,以減少內(nèi)存消耗。)
function bindEvent(){
var obj=document.createElement("XXX");
obj.onclick=function(){
//Even if it's a empty function
}
obj=null;
}
內(nèi)存泄露方式五:
a = {p: {x: 1}};
b = a.p;
delete a.p;
執(zhí)行這段代碼之后b.x的值依然是1.由于已經(jīng)刪除的屬性引用依然存在,因此在JavaScript的某些實現(xiàn)中,可能因為這種不嚴謹?shù)拇a而造成內(nèi)存泄露。所以在銷毀對象的時候,要遍歷屬性中屬性,依次刪除。
內(nèi)存泄露方式六:
自動類型裝箱轉(zhuǎn)換在低版本ie系列中會導致內(nèi)存泄露。
var str="antzone";
console.log(str.length);
str本身是一個string而非object,它沒有l(wèi)ength屬性,所以當訪問length時,JS引擎會自動創(chuàng)建一個臨時String對象封裝str,而這個對象一定會泄露。這個bug匪夷所思,所幸解決起來相當容易,記得所有值類型做.運算之前先顯式轉(zhuǎn)換一下:
var str="antzone";
console.log(new String(str.length);
相關(guān)推薦
-
javascript面向?qū)ο缶幊谈拍詈唵谓榻B
關(guān)于面向?qū)ο筮@個術(shù)語,大家應該都不陌生了,鋪天蓋地都是。但是很多朋友還是不太明白到底什么是面向?qū)ο蟮木幊蹋旅婢陀猛ㄋ椎恼Z言做一下介紹。面向?qū)ο蠛唵蔚恼f就是將功能封裝到對象里,強調(diào)的是具備某種功能的對
-
javascript面向?qū)ο缶幊痰姆菢?gòu)造函數(shù)的繼承
關(guān)于面向?qū)ο蟮姆庋b可以參閱jvscrit面向?qū)ο缶幊剃P(guān)于封裝簡單介紹一章節(jié)。關(guān)于非構(gòu)造函數(shù)的繼承可以參閱jvscrit面向?qū)ο缶幊痰臉?gòu)造函數(shù)的繼承一章節(jié)。一.什么是非構(gòu)造函數(shù)的繼承:比
-
javascript面向?qū)ο缶幊痰臉?gòu)造函數(shù)的繼承
關(guān)于面向?qū)ο蟮姆庋b可以參閱jvscrit面向?qū)ο缶幊剃P(guān)于封裝簡單介紹一章節(jié)。關(guān)于非構(gòu)造函數(shù)的繼承可以參閱jvscrit面向?qū)ο缶幊痰姆菢?gòu)造函數(shù)的繼承一章節(jié)。今天要介紹的是,對象之間的繼承
-
javascript面向?qū)ο缶幊剃P(guān)于封裝簡單介紹
本章節(jié)介紹一下關(guān)于jvscrit面向?qū)ο蟮姆庋b問題。關(guān)于面向?qū)ο蟮睦^承可以參閱如下兩章節(jié):(1).jvscrit面向?qū)ο缶幊痰臉?gòu)造函數(shù)的繼承一章節(jié)。(2).jvscrit面向?qū)ο缶幊?/p>
-
javascript Object類型對象簡單介紹
本章節(jié)簡單一下關(guān)于Objct屬性的創(chuàng)建和使用,需要的朋友可以做一下參考。創(chuàng)建Objct對象的方式有兩種,下面首先做一下介紹。一.使用構(gòu)造函數(shù)方式:vr obj=nw Objct();obj.















