Js內存泄露問題總結


最近接受了一個Js職位的面試,問了很多Js的高級特性,才發現長時間使用已知的特性進行開發而忽略了對這門語言循序漸進的理解,包括Java我想也是一樣,偶爾在Sun官方看到JDK6.0列舉出來的new features才發現很多東西是自己並不知道或者遺忘了的。看來還是要堅持總結技術,反復理解和運用才能保持對任何技術的掌握運用能力阿。

翻了一些Js的新老資料,准備先講講Js的內存泄露問題——
當一個DOM對象包含一個Js對象的引用(例如一個Event Handler), 而這個Js對象又持有對這個DOM對象的引用時,一個環狀引用就行成了。這本身並不是什么錯誤或者Bug,因為Js的回收機制能理解這種環狀的引用結構並且在沒有其他對象能關聯到環上的時候回收這個環上的所有對象內存。可不幸的是IE瀏覽器中的DOM結構並不受Js解釋機制管理,所以它並不能理解這種失去外界引用的環狀結構,導致環上任何對象都無法被訪問到,可是內存依舊占據着,這也就是所謂的Js內存泄露了。

我們來看一個經典的例子說明問題——

JScript code

(function(limit, delay){
var queue=new Array(10);
var n;
function makeSpan(n){
    var s=document.createElement(‘span’);
    document.body.appendChild(s);
    var t=document.createTextNode(‘ ’+n);
    s.appendChild(t);
    s.onclick=function(e){
    s.style.backgroundColor=’red’;
alert(n);
};
return s;
}

function process(n){
    queue.push(makeSpan(n));
    var s=queue.shift();
    if(s)
        s.parentNode.removeChild(s);
}

function loop()}{
    if(n<limit){
    process(n);
    n+=1;
    setTimeout(loop,delay);
}
}
loop();
})(10000,10);

 

這個例子的意義是創建出10000個span元素來添加到DOM的body上,並且對其內容填充序號n,緊接着從queue的第一個位置移除創建的span元素,也就是說10000個為止,不斷的創建再移除,永遠只保留最新創建的那10個。這個例子滿足的條件就是DOM元素帶有Js對象即click事件的Event Handler,而Event Handler里面又帶有這個DOM元素的引用,於是環狀結構行程。

當我在IE上運行這個Js的時候打開任務管理器,很明顯的看到此網頁的內存從55M左右起很穩定的增長直到結束第10000個span創建完畢停止增長時已經到了167M,而在Firefox上運行此Js得到的數據是從頭到尾內存都不會超過70M。這已經說明IE一直都沒有解決這種Js內存泄露的問題,即使我用的版本已經是最新的IE8.0。

可以想象在如今Ajax運用越來越多,用戶體驗要求越來越高的情況下,網頁的體積會越來越龐大,可能很頻繁的Js程序員需要做的事情就是在某個DOM元素例如Div里添加很多Html代碼,用innerHTML賦值進去,然后用戶觸發某事件后又整個替換掉innerHTML,那么被替換以前的Html代碼很可能帶有這樣的環狀結構,導致頁面只要不刷新,內存就會一直泄露着越來越嚴重,直到吃光機器內存。

所以我們提倡人為的打破這種環狀結構, 即在DOM元素被拋棄之前移除綁定在上面的Js Event Handler,移除的方法就涉及到DOM事件模型的討論范圍了,我已在另外一篇討論文章中詳細機講解W3C標准的DOM事件模型和IE的到底有什么區別了,有興趣的可以看一看。

當然瀏覽器廠商特別是IE也希望能負起一定的責任起來,早日大一統,算是為廣大Js程序員造福吧!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM