IE8 內(nèi)存泄露(內(nèi)存一直增長 )的原因及解決辦法

字號:


    最近開發(fā)的時候?qū)撁媸褂昧硕〞r的局部更新,結(jié)果在ie6,7和Firefox下,一切正常,而在ie8下過上幾個小時就瀏覽器就崩潰了,顯示是內(nèi)存溢出,我以為是代碼寫的不好導(dǎo)致內(nèi)存泄露,但是ie6,7又正常,調(diào)查了一下,原來這是ie8的bug。
    問題點
    在IE8中,生成特定Dom節(jié)點所占用的內(nèi)存是不會被釋放的,即使這些節(jié)點被刪除內(nèi)存也不會被釋放。
    內(nèi)存泄露的節(jié)點類型包括:form、button、input、select、textarea、a、img和objec
    其他的大部分節(jié)點類型是不會泄露的,例如:span、div、p、table等等。
    此問題只發(fā)生在IE8,其他瀏覽器不發(fā)生。
    如果用戶按了F5,IE8會重新刷新頁面,首先它會unload window.top,這時候會釋放掉內(nèi)存。如果頁面是iframe,則unload此iframe,沒有任何反應(yīng)??雌饋碇挥衱indow.top被 unload,內(nèi)存才會被釋放。
    例子:
    例1
    執(zhí)行下面的代碼,IE8就會泄露內(nèi)存。
    function leak1() { 
    var node = document.getElementById("TO_AREA"); 
    node.innerHTML = "<img />"; 
    node.innerHTML = ""; 
    node = null; 
    }
    注意:
    * 此例子添加了節(jié)點,所以會泄露。
    * 在中有個div,id為“TO_AREA”。
    * 提醒一下,這里沒有閉包和循環(huán)引用。
    例2
    下面的代碼沒有使用innerHTML,但是還是會泄露
    function leak2() { 
    var node = document.getElementById("FROM_AREA").cloneNode(true); 
    node.id = "NEW_AREA"; 
    document.body.appendChild(node); 
    document.body.removeChild(node); 
    node = null; 
    }
    注意:
    * FROM_AREA 是form的id,而且這里也沒有閉包和循環(huán)引用。
    例3
    這是最簡單,最直接的例子:
    function leak4() { 
    var node = document.createElement("IMG"); 
    document.body.appendChild(node); 
    document.body.removeChild(node); 
    }
    注意:
    * 如果用span來代替img,就不會有泄露了。
    這些例子只在IE8中泄露內(nèi)存,我在Windows XP, Windows Vista, Windows Server 2008, Windows Server 2008 R2和Windows 7 中的IE8都作了測試,而且使用了IE8中的IE7兼容模式和標準模式,每種情況下都會泄露。
    測試頁面
    關(guān)于泄露
    內(nèi)存大小隨著時間的推移而增長,但這并不直接導(dǎo)致瀏覽器崩潰。瀏覽器使用的內(nèi)存好像是有上限的,它似乎會從某些內(nèi)部手段來限制DHTML使用的內(nèi)存。
    內(nèi)存到達上限后,瀏覽器會自動處理,例如彈出對話框,顯示內(nèi)存不足。
    經(jīng)過自己測試發(fā)現(xiàn) IFrame同樣存在這個問題(在IE8下)
    補充:iframe內(nèi)存釋放
    Ext 核心開發(fā)人員Jack的回答是,TabPanelItem在關(guān)閉時并不會對自定義到tab中的元素做特殊處理,這部分工作必須在控件外來完成。另一方面, 相關(guān)資料稱IE在iframe元素的回收方面存在著bug,在通常情況下應(yīng)該將該元素的src屬性值修改為”abort:blank”,并手工將其從 DOM樹上移除,然后把腳本中引用它的變量置空并調(diào)用CollectGarbage()就可以避免iframe不能正?;厥账斐傻膬?nèi)存泄露。
    <script>
    function clearRAM() {
    var frame = document.getElementById("ifr_content");
    frame.src = 'about:blank';
    frame.contentWindow.document.write( '');//清空frame的內(nèi)容
    frame.contentWindow.document.clear();
    frame.contentWindow.close(); //避免frame內(nèi)存泄漏
    if (navigator.userAgent.indexOf('MSIE') >= 0) {
    if (CollectGarbage) {
    CollectGarbage(); //IE 特有 釋放內(nèi)存
    //刪除原有標記
    var tags = document.getElementById("ifrSet");
    tags.removeChild(frame);
    //添加frameset框架
    var _frame = document.createElement('frame');
    _frame.src = '';
    _frame.name = 'content';
    _frame.id = 'ifr_content';
    tags.appendChild(_frame);
    }
    }
    }
    //主動釋放 5秒一次
    setInterval( function() {
    if (navigator.userAgent.indexOf('MSIE') >= 0) {
    if (CollectGarbage) {
    //alert(1)
    CollectGarbage(); //IE 特有 釋放內(nèi)存
    }
    }
    }, 5000) 
    </ script>