<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    backup2007

    導航

    <2009年2月>
    25262728293031
    1234567
    891011121314
    15161718192021
    22232425262728
    1234567

    統計

    公告

    @import url(http://m.tkk7.com/CuteSoft_Client/CuteEditor/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);


    常用鏈接

    留言簿(1)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    我所理解的IE內存泄露

    我所理解的IE內存泄露

                               

    最近在做一些web方面的東西,突然發現IEremoveChild一個元素并釋放了其dom對象的引用之后,在任務管理器中并不能將內存釋放. 這讓我相當郁悶, Google一翻,各種內存泄露的說法,看的我頭暈。最終還是有些收獲。

    測試1

     

    1.不泄露!

    function test2(){

           gb = document.getElementById('garbageBin');

           var i = 0;

           while(i++<10000){

                  var o = document.createElement("<div onclick='foo();'>");

                  gb.appendChild(o);

                  gb.removeChild(o);

           }    

    }

     

    2 或者當即removeChild, 而是過后在另外一個函數中 gb.innerHTML=””

    也不泄露。也就是,在刷新之前,可以把內存釋放出來。

     

    3 如果即不remove又不 gb置空, 則刷新也要不回內存.

     

    4. 如果只是var o = document.createElement("<div onclick='foo();'>"); 其他什么也不做,

    同樣導致泄露。

     

    以上測試在IE7IE6等會再說。 這告訴我們,如果你在創建元素的時候已經關聯了事件處理對象,也就是內聯的foo(), 那么一定要將元素掛載到頁面中的dom樹上, 這樣你才有可能通過remove或者innerHTML=’’的方式回收內存。

     

    我到現在對于內存泄露還有疑惑,到底怎樣才算泄露?

    是刷新頁面之前可以把內存收回才算不泄露,還是刷新之后可以收回內存就算不泄露?

    前輩們給出的MSDN上那個父子div插入順序的例子, 我在IE7中跑, 似乎不像網上說的那樣,結果是有泄露的那個函數,運行完刷新瀏覽器,內存被回收了。而第二個函數內存一直沒長。 這樣理解的話,應該是瀏覽器刷新之前就被回收(不上漲)就算不泄露吧。那么刷新之后還無法收回的算什么呢?更厲害的內存泄露?呵呵。我暈了。

     

    暫且認為:如果在瀏覽器刷新之前, 內存可以被回收,才算不泄露。

    得出:

    規則1:創建的元素,如果包含內聯腳本(這是這條規則的前提情況)一定要掛載在dom樹上!不能先掛載到不在樹上的元素!

    如果不包含內聯腳本對象, 則不會泄露。

    如果包含了內聯腳本,則記得先掛在樹上~ 哈哈 也就是先把父節點掛載,然后掛載子節點到父節點.

    再者說來,在FF等其他瀏覽器中,根本不允許
    document.createElement("<div onclick='foo();'>");
    這樣的代碼出現么!
    所以按照標準的寫法來做是有好處的!

    var o =document.createElement(“div”)

    o.onclick = foo;

    這樣就不會有泄露!

     

    規則2  不討論內聯事件對象的情況,因為那是個特例, 來看這樣的情況

    function test(){

           gb = document.getElementById('garbageBin');

           var i = 0;

           while(i++<5000){

                  (function(){

                  var o = document.createElement("div");

                  //產生循環引用!

                  o.onclick = function(){

                         alert('haha')

                  }

                 

                  gb.appendChild(o)

                 

                  //雖然remove了元素,由于循環引用的存在,無法回收內存

                  //應當在remove之前,打破循環引用!

                  //o.onclick = null; //break!

                  gb.removeChild(o)

                 

                  })();

           }

    }

    注意哈,這此會導致內存泄露,就像前輩們說的那樣, o.onclick = function一句產生了dom元素和function對象的循環引用。就算掛載到dom,然后remove,內存依然不能收回。(似乎能收回一些,但是仍然沒有回到調用前的數值), PF使用率成上升趨勢.
    當然解決方法很簡單, 只要在 removeChild 之前將循環打破即可. 使用o.onclick = null 即可,或者事件響應寫在函數外面。這個網上有很多講,不多說。我關注的其實不是這個,主要是, IE7removeChild到底能做些什么? 刷新頁面的時候,回收的又是哪些內存?

    (如果不append也不remove,則會徹底的泄露,刷新無濟于事.)

    我將紅色的部分,也就是內部包裝的function去掉。循環5000次,內存沒有增長! 我做這樣的猜測:內存泄露是由于循環引用沒錯,然而onclick 關聯的那個function 屬于匿名函數哈,在整個過程中只解析一次,因此無論你循環多少次,泄露的都只是跟這一個對象有關,因此泄露數量很少很少,以至于看不出。

    然而包裝成函數調用5000次呢?就生成了5000onclick關聯的function, 泄露的內容就增大了5000倍,因此我們可以看的出來。

     

    3

    下面測試正常的創建元素。 先測試只創建, append到樹上的情況.

    //IE7下沒有問題,內存不會增長,說明IE7可以動態回收不在結點樹上的并且沒有關//JS對象, 且沒有其他對象引用它的元素.

    function test2(){

           var i = 0;

           while(i++<5000){

                  //(function(){

                         var o = document.createElement("<div>");

                         o.innerHTML = "AAA";

                         //加上下面兩句也沒問題!

                         buf.push(o);//如果后面不做處理,則不會被回收哦

                         buf.pop();   //直接pop掉,也就沒有對象引用這個元素了       

     

                  //})();

                  //buf.pop 放到這里也完全OK,內存不會增長

           }

          

    }

     

     

    也就是說,定義一個dom元素,只要沒有循環引用, appenddom樹上也沒問題。只要沒有被引用到,就會被垃圾回收。

    這幾個例子都是創建一個就刪除一個,那么如果先緩存下來,然后再刪除呢?

    看這個例子:

           var i = 0;

           while(i++<5000){

                 

                  (function(){

                         var o = document.createElement("<div>");

                         o.onclick = foo;

                         o.innerHTML = "AAA";

                        

                         buf.push(o);//如果后面不做處理,則不會被回收哦

                  })();

           }

     

           //直接清空buf

           buf.length = 0;

           /*

           //嘗試逐個置空方法

           for(var i=0;i<buf.length;i++){

                  //document.body.removeChild(buf[i]);

                  buf[i] = null;

           }

           */

           //嘗試pop

           //while(buf.pop());

    該例子先將5000個對象存在buf里,然后再嘗試各種方法去釋放他們,也就是斷開對他們的引用。 然而實驗結果是: 占用較大的內存,而且每次調用這個函數,PF使用率都是相同的! 這說明,內存不會累計增加。 然而也不會立即的釋放。雖然PF使用率數值沒變,但是由于再次調用還是占用這些,說明之前占用的內存被新的內容覆蓋了。然而總體情況,還是沒有得到理想的釋放效果。 很讓人郁悶,為什么創建一個就釋放一個就可以,創建多個然后再釋放就不完全了呢?

    然而這種情況只是在測試,畢竟沒人會去創建一堆不掛載到頁面dom的元素吧~

     

    再來看掛載到dom樹上的情況:

    下面的例子也OK

    while(i++<5000){         

                  (function(){

                         var o = document.createElement("<div>");

                         o.onclick = foo; //因為定義在了外部,沒有循環引用問題

                         o.innerHTML = "AAA";

                         document.body.appendChild(o);

                         document.body.removeChild(o);

                  })();

    }

     

    如果去掉removeChild一行,內存情況也尚好,只是增加一點,這是正常的,畢竟顯示到頁面上需要占用內存。 然而讓我不解的是: 為什么append到頁面就占用很少內存,而保存

    buf里面就會占用很大內存呢??不解!
    而且,如果先append,然后保存到buf里,占用內存依然很少!
    還有如果不設置innerHTML, 則占用內存極少! 里面的原因我就猜不到了.

    我只能得出這樣的結論: IE中,創建一個元素,務必把它掛載到dom樹上! 這樣即使不remove,刷新后內存也會釋放。

     

    如果將刪除代碼移到function外面, 情況一樣,沒有泄露。

     

    再來實驗將5000個對象掛載后,然后再刪除的情況

    我們通過buf保存對象的引用:

           while(i++<10000){

                  var o;

                  (function(){

                         o = document.createElement("<div>");

                         o.onclick = foo;

                         o.innerHTML = "haha";

                         o.style.left="10px";

                         document.body.appendChild(o);

                         buf.push(o);//保存引用

                  })();

           }

           // 這里調用removeChild來釋放

           while(buf.length>0){

                  document.body.removeChild(buf.pop());

           }

    測試結果還不錯,雖然內存會上升,但是多次調用會維持在一個水平上,這說明,每次調用時,新的對象占用舊的對象的內存,因此不會累計增加,還算OK. 

    結論是:同未掛載的情況類似,如果一次性緩存多個對象然后統一removeChild來清除,則IE不會立即釋放內存,如果有新的變量或者對象出現,則會覆蓋那部分內存。總的情況還不差。

     

    使用另一種方式刪除:定義一個看不見的元素gb當做垃圾站

           /*

           while(buf.length>0){

                  //首先說明,一個元素只能掛載到一個點上,因為dom是一個樹結構,

                  //元素對象只是將指針掛載到樹的某個位置,之前對象在body,現在掛載到了

                  //gb,那么body中就不顯示了,而轉到gb上來,

                  //另外如果將一個元素innerHTML置空,意味著其子元素的內存被釋放!

                  //所以,這是一個名副其實的回收站~哈哈

                  gb.appendChild(buf.pop());

                  gb.innerHTML = "";

                 

           }

           */

     

    這種情況得到的結果和上面類似,然而內存占用更少,上面是35M左右,而這個維持在25M左右,情況好了不少。 只是效率低了一點,因為有append操作

    其實如果不做清除的時候,內存占用到了25M. 而清除之后,第一種方法35M,第二種方法25M, 似乎根本沒有清除,其實還是這樣,新的內容會覆蓋舊的內存,只是任務管理器沒有顯示出來。因為如果不清除,多次調用后內存是累計增加的,而清除后會維持在一個水平。

     

    還有pop的速度很慢,改成for會快很多!

    var l=buf.length;

           for(var i=0;i<l;i++){

                  gb.appendChild(buf[i]);

           }

           gb.innerHTML = ""; //置空,子元素全被釋放!

           buf.length = 0;        //重置buf

     

    所以,使用這種方法清除元素是再好不過的了。 可是需要注意的是,如果內部元素有循環引用的現象,清除之前一定要先把循環引用斷開,方法就是遞歸的清除類型為function的屬性。

     

    只要有善于發現循環引用的良好習慣~ 問題就不是問題了~

    posted on 2009-02-12 04:40 backup2007 閱讀(1880) 評論(0)  編輯  收藏 所屬分類: 隨手寫寫


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 日韩精品免费一级视频| 国产无遮挡色视频免费观看性色 | 最新黄色免费网站| 亚洲宅男天堂在线观看无病毒| 好吊妞788免费视频播放| 亚洲人成人77777在线播放| 99在线在线视频免费视频观看 | 亚洲精品国产精品国自产网站| 成人免费观看一区二区| 国产精品久久亚洲不卡动漫| 成人免费a级毛片| 激情小说亚洲图片| 亚洲国模精品一区| 中文字幕手机在线免费看电影| 亚洲精品无码久久久久去q | 亚洲成人福利在线| 亚洲免费视频观看| 亚洲午夜无码久久久久小说| 成人免费毛片观看| 青青青视频免费观看| 亚洲综合无码精品一区二区三区 | 亚洲欧洲免费无码| 亚洲AV成人无码久久WWW| 亚洲综合最新无码专区| 久久精品国产免费一区| 亚洲免费电影网站| 国产一级淫片视频免费看| 三上悠亚在线观看免费| 久久久久亚洲AV成人片| 免费鲁丝片一级观看| 99麻豆久久久国产精品免费| 亚洲国产精品日韩在线观看| 国产成人免费片在线视频观看| 两个人看www免费视频| 亚洲熟妇无码久久精品| 免费人妻无码不卡中文字幕18禁| a视频在线观看免费| 亚洲色偷偷偷综合网| 亚洲中文字幕日产乱码高清app| 亚洲高清中文字幕免费| 人成电影网在线观看免费|