魔鬼的夢魘—驗證IE中的js內存泄露模式(續)


魔鬼的夢魘—驗證IE中的js內存泄露模式(續)

 

         前面幾篇文章我們驗證學習了Justin Rogers文章中提出的集中泄露模式,但是其中並沒有介紹Iframe的內存泄露情況;其中的各種原因,我覺的雖然當時ajax的興起,極大地促進了web應用程序的開發和發展,但是並沒有涉及到大規模的動態更新頁面DOM元素,所以這個時候的泄露都不至於會引起大家的關注;但是隨着大量js類庫框架的出現,特別是extjs的出現,功能豐富界面漂亮美觀,同時提供了大量豐富的前端控件,頓時使人眼前一亮,很多人都會不由的感到震撼,原來bs也可以做出這么優美酷炫的界面;特別是最近移動互聯網的風行,很多復雜的應用都轉移到了前段,這些復雜的應用基本上展現基本上都會涉及到動態創建DOM,同時很多應用也會使用iframe,這就會導致內存泄露的滋生;如果你的應用足夠復雜,那么泄露的情況也會十分嚴重,甚至導致瀏覽器崩潰。

       我們先來看一下“史前時代”,使用iframe是否存在內存泄露,泄露的情況如何?我們新建一個普通的靜態html頁面;然后我們在一個包含iframe的頁面中,通過點擊按鈕不斷的刷新iframe,具體代碼如下    

 iframe嵌套的靜態html頁面  

[html] view plaincopy
<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >  
< html  xmlns ="http://www.w3.org/1999/xhtml" >  
< head >  
     < title ></ title >  
</ head >  
< body >  
    UnLeakIFrameContent  
</ body >  
</ html >  

 

      包含iframe的頁面  

<! DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" >  
< html  xmlns ="http://www.w3.org/1999/xhtml" >  
< head >  
     < title ></ title >  
     < script  type ="text/javascript" >  
         var IFrameLeakTester = {  
            frameTagId: "frame"  
            ,              
            staticDOMUrl: "UnLeakIFrameContent.htm"  
            ,  
            staticLeak:  function () {  
                 var frame = document.getElementById( this.frameTagId);  
                frame.src =  this.staticDOMUrl;  
            }  
        };  
     </ script >  
</ head >  
< body >  
     < div >          
         < input  type ="button"  value  = "staticDOMLeak"  onclick ="IFrameLeakTester.staticLeak();"   />  
     </ div >  
     < div >  
         < iframe  id ="frame"   src ="UnLeakIFrameContent.htm"    height  = "500px"  width  = "100%" >  
              
         </ iframe >  
     </ div >  
</ body >  
</ html >  

 


      從代碼中,我們可以看到沒有任何的循環引用和動態的DOM創建,自然我們刷新整個包含iframe的頁面也不會有內存泄露,使用sIEve測試也證明了這一點。

 

圖 1. 刷新iframe中嵌套靜態網頁內存泄露情況

 

         如果我們不斷的點擊頁面中的按鈕,來不斷的刷新iframe,這個時候是否有內存泄露呢?從下圖的測試數據來看,我們看到泄露的確是存在的,只是泄露的數目並沒有隨刷新的次數遞增,所以我猜想是IE緩存了iframe的頁面對象的DOM。

 

圖 2. Iframe嵌套靜態頁面,不斷刷新iframe的內存泄露情況

 

         那么如果iframe嵌套的頁面有動態創建DOM的邏輯的話,那泄露的情況會怎樣呢?這次嵌套的頁面我們使用extjs中的那個模仿windows桌面的頁面(examples/desktop/desktop.html),我們先來看一下這個頁面本身是否有泄露問題,從圖3中,我們可以看到是沒有泄露問題的。

 

圖 3. 直接刷新extjs的desktop例子泄露情況

 

         接下來我們將iframe的嵌套頁面改成extjs的desktop.html,通過同樣的方式,我們看一下刷新整個頁面和不斷刷新iframe時,來看一下內存泄露的具體情況;詳細代碼如下

         包含iframe的頁面           

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

< html  xmlns ="http://www.w3.org/1999/xhtml" >
< head >
     < title ></ title >
     < script  type ="text/javascript" >
         var IFrameLeakTester = {
            frameTagId: "frame"
            ,
            dynamicDOMUrl: "http://localhost:30000/examples/desktop/desktop.html"
            ,            
            leak:  function () {
                 this._leak( true);
            }
            ,
            unLeak:  function () {
                 this._leak( false);
            }
            ,
            _leak:  function (leak) {
                 var frame = document.getElementById( this.frameTagId);
                 // 網上流傳的方法,但是在這種情況下沒有什么效果
                 if (!leak) {
                     this.clear(frame);
                }
                frame.src =  this.dynamicDOMUrl;
            }
            ,
            clear:  function (frame) {
                 if (frame) {
                    frame.contentWindow.document.write("");
                    frame.contentWindow.document.clear();
                    top.CollectGarbage();
                }
            }
            
        };
     </ script >
</ head >
< body >
     < div >
         < input    type ="button"  value ="dynamicDOMLeak"   onclick ="IFrameLeakTester.leak();" />
         < input  type ="button"  value  = "dynamicDOMUnLeak"  onclick ="IFrameLeakTester.unLeak();"   />        
     </ div >
     < div >
         < iframe  id ="frame"   src ="UnLeakIFrameContent.htm"    height  = "500px"  width  = "100%" >
            
         </ iframe >
     </ div >
</ body >
</ html >

 

圖 4. 刷新嵌套extjs例子的這個頁面內存泄露情況

 

 

圖 5. 不斷刷新嵌套extjs例子的iframe內存泄露情況

 

         從圖4和圖5中,我們可以看到刷新整個頁面也是沒有泄露的,但是刷新iframe卻存在泄露,並且刷新的次數越多泄露越嚴重。綜合前面iframe嵌套靜態頁面的例子,我們可以知道,IE可以緩存頁面本身的DOM,以備再次刷新iframe的同一頁面的時候用;但是如果iframe嵌套的頁面中新建了DOM元素,那么每次打開這個頁面的時候都會新建對應的DOM元素,從而導致嚴重的內存泄露。

         對於怎樣應對這種內存泄露的情況,我沒有發現行之有效的方法;在網上搜到一些解決的方法,但是我測試了一下(單擊dynamicDOMUnLeak按鈕),沒有什么效果,具體情況如下圖

 

圖 6. 解決泄露的代碼沒有效果


免責聲明!

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



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