国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
瀏覽器中的內(nèi)存泄露(重新整理ing)

什么是內(nèi)存泄露

內(nèi)存泄露是指一塊被分配的內(nèi)存既不能使用,又不能回收,直到瀏覽器進(jìn)程結(jié)束。在C++中,因?yàn)槭鞘謩?dòng)管理內(nèi)存,內(nèi)存泄露是經(jīng)常出現(xiàn)的事情。而現(xiàn)在流行的C#Java等語言采用了自動(dòng)垃圾回收方法管理內(nèi)存,正常使用的情況下幾乎不會(huì)發(fā)生內(nèi)存泄露。瀏覽器中也是采用自動(dòng)垃圾回收方法管理內(nèi)存,但由于瀏覽器垃圾回收方法有bug,會(huì)產(chǎn)生內(nèi)存泄露。

內(nèi)存泄露Quick View

不同的瀏覽器中存在各種內(nèi)存泄露方式,目前發(fā)現(xiàn)的主要是這樣幾種:

1.       循環(huán)引用

已經(jīng)確認(rèn)存在泄漏的瀏覽器:IE6.0 FF2.0

含有DOM對(duì)象的循環(huán)引用將導(dǎo)致大部分當(dāng)前主流瀏覽器內(nèi)存泄露 這里有兩個(gè)簡(jiǎn)單的概念

引用:a.屬性=b,a就引用了b

循環(huán)引用:簡(jiǎn)單來說假如a引用了b,b又引用了a,ab就構(gòu)成了循環(huán)引用。

ab循環(huán)引用:

var a=new Object;
var b=new Object;
a.r
=b;
b.r
=a;

a循環(huán)引用自己:

var a=new Object;
a.r
=a;

循環(huán)引用很常見且大部分情況下是無害的,但當(dāng)參與循環(huán)引用的對(duì)象中有DOM對(duì)象或者ActiveX對(duì)象時(shí),循環(huán)引用將導(dǎo)致內(nèi)存泄露。我們把例子中的任何一個(gè)new Object替換成document.getElementById或者document.createElement就會(huì)發(fā)生內(nèi)存泄露了。
盡管這看起來非常容易理解,但是因?yàn)橛衏losure的參與而使事情變得復(fù)雜,有些closure導(dǎo)致的循環(huán)引用很難被察覺。下面是一個(gè)非常常見的動(dòng)態(tài)綁定事件:

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

這個(gè)bindEvent執(zhí)行時(shí)100%會(huì)發(fā)生內(nèi)存泄露,Someone 可能會(huì)問,哪里出現(xiàn)了循環(huán)引用? 關(guān)于closure和scopechain參與的循環(huán)引用比較復(fù)雜,此處暫不深入討論。有一個(gè)簡(jiǎn)單的判斷方式:函數(shù)將間接引用所有它能訪問的對(duì)象。obj.onclick這個(gè)函數(shù)中可以訪問外部的變量obj 所以他引用了obj,而obj又引用了它,因此這個(gè)事件綁定將會(huì)造成內(nèi)存泄露。在IBM的文章中介紹了2種方式解決類似的問題一個(gè)是obj=null,另一個(gè)是把onclick的函數(shù)寫在bindEvent外,重復(fù)人家的我就不說了。簡(jiǎn)單貼下代碼:

function bindEvent()
{
    
var obj=document.createElement("XXX");
    obj.onclick
=onclickHandler;
}
function onclickHandler(){
    
//do something
}

 

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


這兩個(gè)方法都打斷了循環(huán)引用,可以解決問題,但是似乎對(duì)代碼表達(dá)能力造成了一定破壞,假設(shè)有這么一個(gè)問題:

function bindEvent()
{
    
var obj=document.createElement("XXX");
    
var var0="OOXX";//Here is a variable
    obj.onclick=function(){
        alert(var0);
//I want to visit var2 here!
    }
    
return obj;//bindEvent must return obj!
}

好了這下兩種辦法都不行了,假如我把函數(shù)寫外面去,var0肯定訪問不了,假如我把obj弄成null,還怎么return它呢?這并不是空想的需要,這實(shí)際上是一個(gè)用JS定制DOM控件的簡(jiǎn)單抽象:創(chuàng)建DOM元素、設(shè)置私有屬性、綁定事件。所以,我們必須update一下兩個(gè)方法。首先,方法1,為了讓函數(shù)能訪問某些變量,我們可以通過一個(gè)Builder函數(shù)來訂制onclick的外部閉包:

function bindEvent()
{
    
var obj=document.createElement("XXX");
    
var var0="OOXX";//Here is a variable
    obj.onclick= onclickBuilder(var0);//想訪問誰就把誰傳進(jìn)去??!
    return obj;//bindEvent must return obj!
}
function onclickBuilder(var0)//這里跟上面對(duì)應(yīng)上就行了 最好參數(shù)名字也對(duì)應(yīng)上
{
    
return function(){
        alert(var0);
    }
}


第二個(gè)辦法,這個(gè)來自51js的chpn同學(xué),讓obj=null在return 之后執(zhí)行??!

function bindEvent()
{
    
try{
        
var obj=document.createElement("XXX");
        
var var0="OOXX";//Here is a variable
        obj.onclick=function(){
            alert(var0);
//I want to visit var2 here!
        }
        
return obj;//bindEvent must return obj!
    } finally {
        obj
=null;
    }
}

 

2.       某些DOM操作

這是IE系列的特有問題 簡(jiǎn)單的來說就是在向不在DOM樹上的DOM元素appendChild,可能會(huì)發(fā)生內(nèi)存泄露(只是可能,具體原因不明,似乎十分復(fù)雜,下面例子中去掉onClick也可以避免泄露)。所以appendChild的順序可能影響內(nèi)存泄露,來自微軟的例子:

</html>
    
<head>
        
<script language="JScript">
        
function LeakMemory()
        
{
            
var hostElement = document.getElementById("hostElement");
            
// Do it a lot, look at Task Manager for memory response
            for(i = 0; i < 5000; i++)
            
{
                
var parentDiv =
                    document.createElement(
"<div onClick='foo()'>");
                
var childDiv =
                    document.createElement(
"<div onClick='foo()'>");
                
// This will leak a temporary object
                parentDiv.appendChild(childDiv);
                hostElement.appendChild(parentDiv);
                hostElement.removeChild(parentDiv);
                parentDiv.removeChild(childDiv);
                parentDiv 
= null;
                childDiv 
= null;
            }

            hostElement 
= null;
        }


        
function CleanMemory()
        
{
            
var hostElement = document.getElementById("hostElement");
            
// Do it a lot, look at Task Manager for memory response
            for(i = 0; i < 5000; i++)
            
{
                
var parentDiv =
                    document.createElement(
"<div onClick='foo()'>");
                
var childDiv =
                    document.createElement(
"<div onClick='foo()'>");
                
// Changing the order is important, this won't leak
                hostElement.appendChild(parentDiv);
               parentDiv.appendChild(childDiv);
                hostElement.removeChild(parentDiv);
                parentDiv.removeChild(childDiv);
                parentDiv 
= null;
                childDiv 
= null;
            }

            hostElement 
= null;
        }

        
</script>
    
</head>
    
<body>
        
<button onclick="LeakMemory()">Memory Leaking Insert</button>
        
<button onclick="CleanMemory()">Clean Insert</button>
        
<div id="hostElement"></div>
    
</body>
</html>


而在IE7中,貌似為了改善內(nèi)存泄露,IE7采用了極端的解決方案:離開頁面時(shí)回收所有DOM樹上的元素,其它一概不管。但是這不僅沒起到任何作用,反而使問題變得更加復(fù)雜。對(duì)這類問題,除了自覺一點(diǎn)繞開這些惡心的東西,多用innerHTML這種無用的建議之外。我想可以通過覆蓋document.createElement來略為改善:
首先我們定義一個(gè)看不見的元素當(dāng)作垃圾箱,所有新創(chuàng)建的元素都扔進(jìn)垃圾箱里,這樣保證了所有DOM元素都在DOM樹上,IE7就可以正確回收了,另一方面也能避免所謂的"appendChild順序不對(duì)導(dǎo)致內(nèi)存泄露"。
function MemoryFix(){
    
var garbageBox=document.createElement("div");
    garbageBox.style.display
="none";
    document.body.appendChild(garbageBox);
    
var createElement=document.createElement;
    document.createElement
=function(){
        
var obj=Function.prototype.apply.apply(createElement,[document,arguments]);
        garbageBox.appendChild(obj);
        
return obj;
    }
}

 

3.       自動(dòng)類型裝箱轉(zhuǎn)換

別不相信,下面的代碼在ie系列中會(huì)導(dǎo)致內(nèi)存泄露

var s=”lalala”;
alert(s.length);

s本身是一個(gè)string而非object,它沒有length屬性,所以當(dāng)訪問length時(shí),JS引擎會(huì)自動(dòng)創(chuàng)建一個(gè)臨時(shí)String對(duì)象封裝s,而這個(gè)對(duì)象一定會(huì)泄露。
這個(gè)bug匪夷所思,所幸解決起來相當(dāng)容易,記得所有值類型做.運(yùn)算之前先顯式轉(zhuǎn)換一下:

var s="lalala";
alert(
new String(s).length);



參考


Understanding and Solving Internet Explorer Leak Patterns(中文版)
Memory leak patterns in JavaScript(中文版)
51js的一則討論 
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
Js內(nèi)存泄漏及解決方案
Javascript內(nèi)存管理機(jī)制
實(shí)現(xiàn)asp.net Treeview的自選父背選擇,或者父親選擇子全選
Understanding and Solving Internet Explorer L...
許愿墻的制作
HTML DOM
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服