問題描述:
在一個搜尋中發現了一個記憶體洩漏的問題,如圖所示:
#搜尋15次,記憶體由15MB上升到18MB,還是比較嚴重的。
問題排查
#經過調試分析,最後定位到問題的大致位置:
function searchData() {
console.log('search');
var sc = {};
// 获取类名为fui-form下的所有mini控件,遍历将搜索条件形成下面的格式
// {
// "控件id":"控件值"
// }
mini.getChildControls(document.getElementsByClassName('fui-form')[0]).forEach(function (item) {
sc[item.id] = item.getValue();
});
console.log('搜索条件' + JSON.stringify(sc, 0, 4));
grid.load();
}
將其除grid.load()
之外的全部註解掉,搜尋0次、1次、10次結果如下:
#可以看出記憶體搜尋次數的增加,記憶體是不成長的,不存在記憶體洩漏問題。
接著以為是console
的問題,註解掉兩個console
,結果如下(仍是搜尋0次、1次、10次):
#問題依舊,可以看出不是console的問題,其實想想也不可能,但是排查時候基本上就是病急亂投醫了。
下面基本上可以定位問題是這一段導致的了。
var sc = {};
mini.getChildControls(document.getElementsByClassName('fui-form')[0]).forEach(function (item) {
sc[item.id] = item.getValue();
});
為了分析,可以將上面拆成兩個部分:取得控制項數組和遍歷組織資料
var sc = {};
var controls = mini.getChildControls(document.getElementsByClassName('fui-form')[0]);
controls.forEach(function (item) {
sc[item.id] = item.getValue();
});
進行獲取與遍歷的拆分之後,再進行測試,問題居然不存在了,如圖:
#最終問題
#函數中取得控制項並遍歷的兩種寫法
寫法一:
// 获取并遍历
mini.getChildControls(document.getElementsByClassName('fui-form')[0]).forEach(function (item) {
sc[item.id] = item.getValue();
});
寫法二:
// 获取控件
var controls = mini.getChildControls(document.getElementsByClassName('fui-form')[0]);
// 遍历
controls.forEach(function (item) {
sc[item.id] = item.getValue();
});
為何寫法一存在記憶體洩漏,而寫法二不存在?
並不一定是內存洩漏,還有可能是gc 沒有進行回收,第一種寫法中語句沒有結束,需要對所有的dom 保持引用,而第二點上一個語句結束,有可能gc 進行了回收dom節點,單純從你測試的次數和時間上不能確定是否第一種寫法是不是真的dom 最終不會回收。
你應該對比15.9 和15.6 這兩次的數據,在表格的左上角有一個comparison ,就是你圖中的summary 的部分,對比一下15.9 和15.6 究竟多了什麼,點開看看黃色的部分,代表持續引用。再假如運行運行多次記憶體仍然不減少,才能判斷為記憶體洩漏。