1. 程式人生 > >點選導航欄,ie8 下記憶體遞增的原因及其解決方法(主要是圍繞是否是iframe導致的)

點選導航欄,ie8 下記憶體遞增的原因及其解決方法(主要是圍繞是否是iframe導致的)

最近幾個專案中均遇到這樣的一個問題:點選導航欄ie8 下記憶體遞增
該如何解決?
首先要明白2個概念:記憶體溢位和記憶體洩露;
記憶體溢位 out of memory,是指程式在申請記憶體時,沒有足夠的記憶體空間供其使用,出現out of memory;比如申請了一個integer,但給它存了long才能存下的數,那就是記憶體溢位。
記憶體洩露 memory leak,是指程式在申請記憶體後,無法釋放已申請的記憶體空間,一次記憶體洩露危害可以忽略,不斷點選,記憶體不斷增加。所以記憶體洩露堆積後果很嚴重,無論多少記憶體,遲早會被佔光。
2者的關係:memory leak會最終會導致out of memory!


記憶體洩漏可以分為4類
1. 常發性記憶體洩漏。發生記憶體洩漏的程式碼會被多次執行到,每次被執行的時候都會導致一塊記憶體洩漏。
2. 偶發性記憶體洩漏。發生記憶體洩漏的程式碼只有在某些特定環境或操作過程下才會發生。常發性和偶發性是相對的。對於特定的環境,偶發性的也許就變成了常發性的。所以測試環境和測試方法對檢測記憶體洩漏至關重要。
3. 一次性記憶體洩漏。發生記憶體洩漏的程式碼只會被執行一次,或者由於演算法上的缺陷,導致總會有一塊僅且一塊記憶體發生洩漏。比如,在類的建構函式中分配記憶體,在解構函式中卻沒有釋放該記憶體,所以記憶體洩漏只會發生一次。
4. 隱式記憶體洩漏。程式在執行過程中不停的分配記憶體,但是直到結束的時候才釋放記憶體。嚴格的說這裡並沒有發生記憶體洩漏,因為最終程式釋放了所有申請的記憶體。但是對於一個伺服器程式,需要執行幾天,幾周甚至幾個月,不及時釋放記憶體也可能導致最終耗盡系統的所有記憶體。所以,我們稱這類記憶體洩漏為隱式記憶體洩漏。
不幸運的是,我們專案中出現的都是常發性記憶體洩漏。
下面細說下我們公司常發性記憶體洩露的剖析:(我們公司的內容基本都是通過iframe巢狀的,故主要是排查是不是此原因。)
第一:每點選一次,記憶體便增加;若增加很多,代表你頁面本身寫法不符合規範,譬如引入大量重複的js檔案等等,迴圈引用dom節點;請先解決這個問題,再繼續往下。
第二:不斷點選,不斷點選,看看是否會出現增加到一定程度,將不再增加。若是,說明記憶體清除起作用了。若否,請先執行:在iframe關閉時,需要清除裡面的dom元素,且讓iframe指向一個空白的頁面。即如下程式碼:

var el = document.getElementById("IFrame1");
            if (el) {
                iframe = el.contentWindow;                
                //清除文件
                el.src = 'about:blank';
                try {
                    iframe.document.write('');
                    iframe.document.clear();
                    CollectGarbage();
                } catch
(e) { }; //清除節點 var _parentElement = el.parentNode; if (_parentElement) { _parentElement.removeChild(el); } }

第三:使用上述方法後,重新載入iframe時都會釋放一定的記憶體(可以從程序中看到記憶體的變化),但載入後新增的記憶體比釋放的記憶體要多很多,再多次載入後還是會導致記憶體溢位。
第四:先看看是不是IE的bug,用下CollectGarbage()函式進行垃圾回收。若此函式沒有效果,可能表明記憶體溢位不僅僅在IE存在,火狐和谷歌瀏覽器有,只是溢位程度較輕。
第五:請使用$.get替換iframe動態載入html,看看記憶體是否繼續增加。
程式碼如下:

$.get(src, function (data) { //初始將a.html include div#iframe
                    $("#center").empty();
                    $("#center").html(data);
                });

若是,則代表和iframe無關。請執行第一個環節中的頁面本身不規範的問題。