【拒绝拖延】常见的JavaScript内存泄露缘由及解决方案

前言

内存泄漏指因为疏忽或错误形成程序未能释放已经再也不使用的内存。内存泄漏并不是指内存在物理上的消失,而是应用程序分配某段内存后,因为设计错误,致使在释放该段内存以前就失去了对该段内存的控制,从而形成了内存的浪费。这里就讲一些常见会带来内存泄露的缘由。javascript

0. 全局变量

JavaScript自由的其中一种方式是它能够处理没有声明的变量:一个未声明的变量的引用在全局对象中建立了一个新变量。在浏览器的环境中,全局对象是window。
function foo(){
  name = '前端曰';
}
// 实际上是把name变量挂载在window对象上
function foo(){
  window.name = '前端曰';
}

// 又或者
function foo(){
  this.name = '前端曰';
}
foo() // 其实这里的this就是指向的window对象

这样无心中一个意外的全局变量就被建立了,为了阻止这种错误发生,在你的Javascript文件最前面添加 'use strict;' 。这开启了解析JavaScript的阻止意外全局的更严格的模式。或者本身注意好变量的定义!前端

1. 循环引用

在js的内存管理环境中,对象 A 若是有访问对象 B 的权限,叫作对象 A 引用对象 B。引用计数的策略是将“对象是否再也不须要”简化成“对象有没有其余对象引用到它”,若是没有对象引用这个对象,那么这个对象将会被回收 。java

function func() {  
    let obj1 = {};  
    let obj2 = {};  
  
    obj1.a = obj2; // obj1 引用 obj2  
    obj2.a = obj1; // obj2 引用 obj1  
}

当函数 func 执行结束后,返回值为 undefined,因此整个函数以及内部的变量都应该被回收,但根据引用计数方法,obj1 和 obj2 的引用次数都不为 0,因此他们不会被回收。要解决循环引用的问题,最好是在不使用它们的时候手工将它们设为空。node

解决方案:obj1obj2 都设为 null浏览器

2. 老生常谈的闭包

闭包:匿名函数能够访问父级做用域的变量。闭包

var names = (function(){  
    var name = 'js-say';
    return function(){
        console.log(name);
    }
})()

闭包会形成对象引用的生命周期脱离当前函数的上下文,若是闭包若是使用不当,能够致使环形引用(circular reference),相似于死锁,只能避免,没法发生以后解决,即便有垃圾回收也仍是会内存泄露。函数

3. 被遗忘的延时器/定时器

在咱们的平常需求中,可能会常常试用到 setInterval/setTimeout ,可是使用完以后一般忘记清理。this

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/clearTimeoutspa

4. DOM引发的内存泄露

  • 未清除DOM引用
var refA = document.getElementById('refA');
document.body.removeChild(refA);
// #refA不能回收,由于存在变量refA对它的引用。将其对#refA引用释放,但仍是没法回收#refA。

解决方案:refA = null设计

  • DOM对象添加的属性是一个对象的引用
var MyObject = {}; 
document.getElementById('myDiv').myProp = MyObject;

解决方案:在页面 onunload 事件中释放 document.getElementById('myDiv').myProp = null;

DOM被删除或清空没有清楚绑定事件这种状况应该是比较常见的,同时也应该是比较容易被忽略的。

  • 给DOM对象绑定事件
var btn = document.getElementById("myBtn"); 
btn.onclick = function(){ 
    document.getElementById("myDiv").innerHTML = "wechat: js-say"; 
}

document.body.removeChild(btn);
btn = null;

这里把DOM移除了,可是绑定的事件仍没被移除,会引发内存泄露因此须要清除事件。

var btn = document.getElementById("myBtn"); 
btn.onclick = function(){ 
  btn.onclick = null;
    document.getElementById("myDiv").innerHTML = "wechat: js-say"; 
}

document.body.removeChild(btn);
btn = null;

小广告

我本身运营的公众号,记录我本身的成长!

每周至少一篇博客,拒绝拖延从我作起!

公众号:前端曰

公众号ID:js-say

ps:是(yue)不是(ri)

相关文章
相关标签/搜索