javascript內存泄漏的原因:1、全局變量使用不當;2、閉包使用不當;3、延時器或定時器沒有被清除;4、沒有清理的DOM元素引用(dom清空或刪除時,事件未清除)。
本教程操作環境:windows7系統、javascript1.8.5版、Dell G3電腦。
內存泄露是指一塊被分配的內存既不能使用,又不能回收,直到瀏覽器進程結束。即指由于疏忽或錯誤造成程序未能釋放已經不再使用的內存。 內存泄漏并非指內存在物理上的消失,而是應用程序分配某段內存后,由于設計錯誤,導致在釋放該段內存之前就失去了對該段內存的控制,從而造成了內存的浪費。這里就講一些常見會帶來內存泄露的原因。
1. 全局變量
JavaScript可以處理沒有聲明的變量:一個未聲明的變量的引用在全局對象中創建了一個新變量。在瀏覽器的環境中,全局對象是window。
function foo(){ name = '前端曰'; } // 其實是把name變量掛載在window對象上 function foo(){ window.name = '前端曰'; } // 又或者 function foo(){ this.name = '前端曰'; } foo() // 其實這里的this就是指向的window對象
這樣無意中一個意外的全局變量就被創建了,為了阻止這種錯誤發生,在你的Javascript文件最前面添加 ‘use strict;’ 。這開啟了解析JavaScript的阻止意外全局的更嚴格的模式。或者自己注意好變量的定義!
2. 閉包
閉包:匿名函數可以訪問父級作用域的變量。
var names = (function(){ var name = 'js-say'; return function(){ console.log(name); } })()
閉包會造成對象引用的生命周期脫離當前函數的上下文,如果閉包使用不當,可以導致環形引用(circular reference),類似于死鎖,只能避免,無法發生之后解決,即使有垃圾回收也還是會內存泄露。
3. 被遺忘的延時器/定時器
在我們的日常需求中,可能會經常試用到 setInterval/setTimeout ,但是使用完之后通常忘記清理。
var someResource = getData(); setInterval(function() { var node = document.getElementById('Node'); if(node) { // 處理 node 和 someResource node.innerHTML = JSON.stringify(someResource)); } }, 1000);
setInterval/setTimeout 中的 this 指向的是window對象,所以內部定義的變量也掛載到了全局;if 內引用了 someResource 變量,如果沒有清除 setInterval/setTimeout 的話someResource 也得不到釋放;同理其實 setTimeout 也一樣。所以我們用完需要記得去 clearInterval/clearTimeout。
4、沒有清理的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() { document.body.removeChild(document.getElementById('button')); // 此時,仍舊存在一個全局的 #button 的引用 // elements 字典。button 元素仍舊在內存中,不能被 GC 回收。 }
【推薦學習:javascript高級教程】