前言
今天寫一下javascript導致內存泄露的幾種方式,及我們在平時工作中,如何通過谷歌瀏覽器查看內存使用情況。我前面的文章制作公司數據大屏的幾點技術總結 ,里面用到了不少setInterval,setInterval用多了,會占用大量的內存,要我們必須及時清理,否則,運行時間一長,極有可能導致瀏覽器崩潰!
幾種常見的js內存泄露
1、意外的全局變量
JavaScript 處理未定義變量的方式比較寬松:未定義的變量會在全局對象創建一個新變量。在瀏覽器中,全局對象是 window 。
例如:
haorooms ="這是一個全局的haorooms"
實際上生成了一個全局的haorooms,雖然一個簡單的字符串,無傷大雅,也泄露不了多少內存,但是我們在編程中盡量少的避免全局變量!
另外一種全局變量可能由this創建。例如:
function foo() { this.variable = "potential accidental global"; } // Foo 調用自己,this 指向了全局對象(window) foo();
2、沒有及時清理的計時器或回調函數
本文剛剛開始的時候,我就說了setInterval用多了,會占用大量的內存。因此setInterval我們必須及時清理!可以用如下方式清理setInterval。
function b() { var a = setInterval(function() { console.log("Hello"); clearInterval(a); b(); }, 50); } b();
或者用2個函數:
function init() { window.ref = window.setInterval(function() { draw(); }, 50); } function draw() { console.log('Hello'); clearInterval(window.ref); init(); } init();
或者我們用setTimeout
function time(f, time) { return function walk() { clearTimeout(aeta); var aeta =setTimeout(function () { f(); walk(); }, time); }; } time(updateFormat, 1000)();
3、脫離 DOM 的引用
有時,保存 DOM 節點內部數據結構很有用。假如你想快速更新表格的幾行內容,把每一行 DOM 存成字典(JSON 鍵值對)或者數組很有意義。此時,同樣的 DOM 元素存在兩個引用:一個在 DOM 樹中,另一個在字典中。將來你決定刪除這些行時,需要把兩個引用都清除。
var elements = { button: document.getElementById('button'), image: document.getElementById('image'), text: document.getElementById('text') }; function doStuff() { image.src = 'http://some.url/image'; button.click(); console.log(text.innerHTML); // 更多邏輯 } function removeButton() { // 按鈕是 body 的后代元素 document.body.removeChild(document.getElementById('button')); // 此時,仍舊存在一個全局的 #button 的引用 // elements 字典。button 元素仍舊在內存中,不能被 GC 回收。 }
4、閉包
閉包注意事項我之前提及過,請看文章 http://www.haorooms.com/post/qianduan_xnyhbc
5、echart不停調用導致內存泄露
不停的用setInterval調用echart,更新echart表格及地圖數據,及時清理了setInterval,也會導致內存泄露!
解決辦法:
首先及時清理:
myChart.clear(); myChart.setOption(option);
但是你會發現,作用不大,那么如何處理呢?
我是如下做的:
第一次處理用
myChart.clear(); myChart.setOption(option);
后面用setInterval的時候,我是如下寫的:
mapCharts.setOption({ series: [{ data: _this.convertData(mapdata) }, { data: _this.convertData(mapdata.sort(function (a, b) { return b.value - a.value; }).slice(1, 6)), }, { data: _this.convertData(mapdata.sort(function (a, b) { return b.value - a.value; }).slice(0, 1)) }] },{notMerge: false, lazyUpdate: false, silent:false});
僅僅重新設置了series里面的數據,不是全部setOption(option);這樣就不會內存泄露了!
谷歌瀏覽器查看內存使用
使用 Chrome 任務管理器作為內存問題調查的起點。 任務管理器是一個實時監視器,可以告訴您頁面當前正在使用的內存量。
按 Shift+Esc 或者轉到 Chrome 主菜單並選擇 More tools > Task manager,打開任務管理器。
使用 Timeline 記錄可視化內存泄漏
使用 Chrome DevTools 的 Timeline 面板可以記錄和分析您的應用在運行時的所有活動。 這里是開始調查應用中可覺察性能問題的最佳位置。
Timeline 面板包含以下四個窗格:
1、Controls。開始記錄,停止記錄和配置記錄期間捕獲的信息。
2、Overview。 頁面性能的高級匯總。
FPS。每秒幀數。綠色豎線越高,FPS 越高。 FPS 圖表上的紅色塊表示長時間幀,很可能會出現卡頓。
CPU。 CPU 資源。此面積圖指示消耗 CPU 資源的事件類型。
NET。每條彩色橫杠表示一種資源。橫杠越長,檢索資源所需的時間越長。 每個橫杠的淺色部分表示等待時間(從請求資源到第一個字節下載完成的時間)。
3、火焰圖。 CPU 堆疊追蹤的可視化。
您可以在火焰圖上看到一到三條垂直的虛線。藍線代表 DOMContentLoaded 事件。 綠線代表首次繪制的時間。 紅線代表 load 事件。
深色部分表示傳輸時間(下載第一個和最后一個字節之間的時間)。
橫杠按照以下方式進行彩色編碼:
HTML 文件為藍色。
腳本為黃色。
樣式表為紫色。
媒體文件為綠色。
其他資源為灰色。