由于疏忽或者错误造成程序未能释放已经不再使用的内存,不再用到的内存却没有及时释放,从而造成内存上的浪费。
原因
意外的全局变量
由于 js 对未声明变量的处理方式是在全局对象上创建该变量的引用。如果在浏览器中,全局对象就是 window 对象。变量在窗口关闭或重新刷新页面之前都不会被释放,如果未声明的变量缓存大量的数据,就会导致内存泄露。
1 2 3 4
| function fn() { a = "global variable"; } fn();
|
- 使用 this 创建的变量(this 的指向是 window)。
1 2 3 4
| function fn() { this.a = "global variable"; } fn();
|
解决方法
- 避免创建全局变量
- 使用严格模式,在 Javascript 文件头部或函数的顶部加上
use strict
闭包引起的内存泄露
闭包可以读取函数内部的变量,然后让这些变量始终保存在内存中。如果在使用结束后没有将局部变量清除,就可能导致内存泄露。
1 2 3 4 5 6
| function fn() { var a = "I'm a"; return function () { console.log(a); }; }
|
解决: 将事件处理函数定义在外部,解除闭包,或者在定义事件处理函数的外部函数中。
比如:在循环中的函数表达式,能复用最好放到循环外面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| for (var k = 0; k < 10; k++) { var t = function (a) { console.log(a); }; t(k); }
function t(a) { console.log(a); } for (var k = 0; k < 10; k++) { t(k); } t = null;
|
没有清理的 DOM 元素引用
虽然别的地方删除了,但是对象中还存在对 dom 的引用。
1 2 3 4 5 6 7 8 9 10 11 12 13
| var elements = { btn: document.getElementById("btn"), }; function doSomeThing() { elements.btn.click(); }
function removeBtn() { document.body.removeChild(document.getElementById("button")); }
|
解决: 手动删除,elements.btn = null
被遗忘的定时器或者回调
定时器中有 dom 的引用,即使 dom 删除了,但是定时器还在,所以内存中还是有这个 dom
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var serverData = loadData(); setInterval(function () { var renderer = document.getElementById("renderer"); if (renderer) { renderer.innerHTML = JSON.stringify(serverData); } }, 5000);
var btn = document.getElementById("btn"); function onClick(element) { element.innerHTMl = "I'm innerHTML"; } btn.addEventListener("click", onClick);
|
解决:
- 手动删除定时器和 dom。
removeEventListener
移除事件监听