JS内存泄露及解决方案

1,211 阅读2分钟

JS内存泄露及解决方案

什么叫内存泄露?

官方解释:内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。通俗点就是指由于疏忽或者错误造成程序未能释放已经不再使用的内存,不再用到的内存却没有及时释放,从而造成内存上的浪费。当内存泄露过多之后就会造成内存溢出问题。

常见的js内存泄漏

1.意外的全局变量

在js中,一个未声明变量的使用,会在全局对象中创建一个新的变量;在浏览器环境下,全局对象就是window:

function foo() {
    demo  = 'test'
}
// 上面的写法等价于
function foo() {
    window.demo = 'test'
}
​
// ---或者---
function foo() {
this.demo = 'test'
// 函数自身发生调用,this指向全局对象window
}
foo();

上面的demo变量应该是foo()内部作用域变量的引用,由于没有使用var来声明这个变量,这时变量demo就被创建成了全局变量,这个就是错误的,会导致内存泄漏。

解决方式: 在js文件开头添加 ‘use strict',开启严格模式。(或者一般将使用过后的全局变量设置为 null 或者将它重新赋值,这个会涉及的缓存的问题,需要注意)

2. 计时器和回调函数timers

定时器setInterval或者setTimeout在不需要使用的时候,没有被clear,导致定时器的回调函数及其内部依赖的变量都不能被回收,这就会造成内存泄漏。

解决方式:当不需要interval或者timeout的时候,调用clearInterval或者clearTimeout

3. DOM泄漏

  • 给DOM对象添加的属性是一个对象的引用
var demo = {};
document.getElementById('id').diyProp = demo;

解决方法:在window.onload时间中加上 document.getElementById('id').diyProp = null;

  • 元素引用没有清理
var demo = document.getElementById('id');
document.body.removeChild(demo);
// 因为存在变量demo对它的引用。虽然我们用了removeChild,但是还在对象里保存着元素的引用,即DOM元素还在内存里面。

解决方法: demo = null;

  • 事件的绑定没有移除

解决方法: 移除时间的监听

4. 闭包

函数范围内的变量将在函数退出调用堆栈后被清除,如果函数外没有任何引用指向它们。尽管函数已经完成执行,并且它的执行上下文和变量环境早已消失,闭包仍将保持变量的引用和存在。

解决方法:闭包是不可避免的,也是JavaScript不可或缺的一部分,所以重要的是:

了解闭包是何时创建的以及它保留了哪些对象,了解闭包的预期生命周期和用途(尤其是作为回调使用时)。