最近爲了知足一部分朋友的需求,給 zTree 提供了 destroy 的方法,用於讓 zTree 自行清空。爲了檢查該方法是否有效,作了一個簡單的測試——顯示5000個節點而後清空,此操做循環100次,結果發現 IE9 下內存嚴重暴漲,因而進行了反覆篩查,最終鎖定了嫌疑犯:關聯數組(data[key] = value)致使的內存泄漏!json
只找到了嫌疑犯不行,定罪要有證據的,設計了一個簡單的模型專門進行這個狀況的測試,不排除可能因爲個人疏忽獲得的錯誤的結論,所以很是歡迎你們踊躍發表本身的見解,隨便噴吧。。。。數組
【測試模型】瀏覽器
不要DOM和閉包、匿名函數干擾,一個全局變量 data 用於保存生成的數據;一個全局變量max用於設置數據最大條數;一個Function用於建立數據;一個Function 用於銷燬數據。兩個按鈕,分別用於觸發這兩個Function。閉包
補充:爲了進行多種狀況對比,所以一共製做了8組建立數據、銷燬數據的 Function ,詳細見後面的說明。架構
【測試流程】函數
【測試環境】性能
Win7 64位操做系統;IE Tester下的 IE六、八、9;FireFox v14.0.1;Chrome v21.0.1180.79;IE6性能太差,所以設置數據條數 max=100000;其餘的瀏覽器都設置 max=1000000;測試
【開始測試】spa
建立對象:關聯數組的 key 值無限遞增,毫不重複操作系統
銷燬對象:遞歸遍歷對象內部屬性,逐一清空
var data = new Object(); var i=0,j, max=1000000; function initJson_1(){ for (j=i+max; i<j; i++) { data["_" + i] = {id:i, name:"name" + i}; } } function clearJson_1(){ clearItem(data); } function clearItem(jsonObj) { for (var s in jsonObj) { var obj = jsonObj[s]; if (obj instanceof Array) { for(var i=obj.length-1; i>=0; i--) { clearItem(obj[i]); obj.pop(); } }else if (obj instanceof Object){ clearItem(obj) }else{ } jsonObj[s] = null; delete jsonObj[s]; } jsonObj = null; }
測試結果:
測試分析:
這種遞歸逐一清空對象屬性的方法對於 IE6 和 Chrome 有必定效果,FireFox杯具了直接無響應(縮小max值後能夠正常);IE8內存暴漲,貌似與這個清空的方法有關,第三次以後再執行方法就無反應了;IE9內存穩步上升,即便最後刷新頁面也仍然佔有大量內存。
建立對象:關聯數組的 key 值無限遞增,毫不重複
銷燬對象:直接將 data 設置爲 new Object()
var data = new Object(); var i=0, max=1000000; function initJson_2(){ for (j=i+max; i<j; i++) { data["_" + i] = {id:i, name:"name" + i}; } } function clearJson_2(){ data = null; data = new Object(); }
測試結果:
測試分析:
與第一組對比,很明顯清空對象直接設置爲 new Object 便可,徹底沒有必要本身遞歸逐一清空,那樣只會起到副作用(明顯下降效率)。此次的清空操做並不會馬上讓垃圾回收機制工做,但對於非IE9 的瀏覽器都能在從新建立對象時進行垃圾回收,IE9繼續保持內存增加狀態。
建立對象:關聯數組的 key 值固定,每次建立都在固定範圍內
銷燬對象:直接將 data 設置爲 new Object()
var data = new Object(); var i=0,j, max=1000000; function initJson_3(){ for (i=0; i<max; i++) { data["_" + i] = {id:i, name:"name" + i}; } } function clearJson_3(){ data = null; data = new Object(); }
測試結果:
測試分析:
由於key值被固定了範圍,反覆測試都會生成一樣的key,因此IE9的內存在增加兩次後就再也不上漲了。另外此次測試也能夠看出FireFox 和 Chrome的垃圾回收機制會在其認爲須要的時候自動執行。
建立對象:關聯數組的 key 值無限遞增,毫不重複
銷燬對象:直接將 data 設置爲 {}
var data = new Object(); var i=0,j, max=1000000; function initJson_4(){ for (j=i+max; i<j; i++) { data["_" + i] = {id:i, name:"name" + i}; } } function clearJson_4(){ data = null; data = {}; }
測試結果:
測試分析:
本組測試主要是與第二組測試進行對照,代表釋放對象將其設置爲 {} 或 new Object() 是沒有什麼區別的。
建立對象:關聯數組的 key 值無限遞增,毫不重複,同時利用 eval 實現 data.key = value方式進行賦值
銷燬對象:直接將 data 設置爲 {}
var data = new Object(); var i=0,j, max=1000000; function initJson_5(){ for (j=i+max; i<j; i++) { eval('data._'+i+'= {id:i, name:"name" + i};'); } } function clearJson_5(){ data = null; data = {}; }
測試結果:
測試分析:
此次改變只能證實eval 能不用的時候千萬別用! 竟然把IE9 搞死了;IE8內存很高,但由於無內存泄漏的狀況因此沒有死掉。並且其餘的瀏覽器在測試時速度也都明顯降低。
建立對象:將 data 設置爲 Array,關聯數組的 key 值無限遞增,毫不重複,且 key 仍爲 String
銷燬對象:直接將 data 設置爲 null
var data = new Object(); var i=0,j, max=1000000; function initJson_6(){ data = []; for (j=i+max; i<j; i++) { data["_" + i] = {id:i, name:"name" + i}; } } function clearJson_6(){ data = null; }
測試結果:
測試分析:
繼續與第二組測試進行對比,會發現data 是 Array 仍是 Object,若是都用關聯數組的方式,仍然用對象的方式使用,測試結果依舊是惟有IE9不斷攀升呀。
建立對象:將 data 設置爲 Array,關聯數組的 key 值無限遞增,毫不重複,且 key 修改成 number,能夠直接使用數組模型
銷燬對象:直接將 data 設置爲 null
var data = new Object(); var i=0,j, max=1000000; function initJson_7(){ data = []; for (j=i+max; i<j; i++) { data[i] = {id:i, name:"name" + i}; } } function clearJson_7(){ data = null; }
測試結果:
測試分析:
採用了純數組的方式保存value,及時index不斷上漲,仍然不會形成瀏覽器的內存無限上漲,IE9也正常了。
建立對象:將 data 設置爲 Array,關聯數組的 key 值固定,每次建立都在固定範圍內,且 key 修改成 number,能夠直接使用數組模型
銷燬對象:利用 pop() 方法逐一刪除數組元素,最後將 data 設置爲 null
var data = new Object(); var i=0,j, max=1000000; function initJson_8(){ data = []; for (i=0; i<max; i++) { data[i] = {id:i, name:"name" + i}; } } function clearJson_8(){ while(data.length>0) { data.pop(); } data = null; }
測試結果:
測試分析:
與第一組測試對比會發現IE8對於用js 逐一清空對象的操做貌似依然有一些性能的損失;IE6最悲催,與第一組測試中的FireFox 同樣,在逐一清空對象時倒下了(縮小max值後能夠正常)。
【測試總結】
【解決建議】