JavaScript垃圾回收机制和内存泄漏

在C# java javascript等语言中,都有自己的垃圾回收机制。垃圾回收机制其实很简单,说白了就是找出不再用的变量,然后释放掉其所占的内存,以便更多进程能进入到内容。那么我们怎样才能知道哪些变量没有用了呢?一般我们采用2种垃圾回收算法。
-------标记-清除
--------引用计数

2012起所有现代浏览器的都才用了标记-清除垃圾回收算法,而较老版本的一些浏览器仍是采用引用计数的算法。
 

标记-清除

这是javascript最常用的垃圾回收算法。其原理就是,当变量进入到执行环境时,就标记其的状态为“进入环境”,当变量离开环境时,其就会清除之前的标记,再将该变量标为“离开环境”,最后,垃圾收集器就会完成内容释放并销毁带有‘离开环境’标记的变量。

但是,标记-清除有个问题就是,释放后的内存空间不是连续的,导致产生很多的内存碎片。这时标记-整理方法就会出场,将占用着内容的对象往一端移动,清除边界的内容,以整理出连续的内存空间。

 

引用计数

引用计算的原理是跟踪每个值被引用的总次数,每当声明了一个变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加 1,如果该变量的值变成了另外一个,则这个值得引用次数减 1,当这个值的引用次数变为 0 的时候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运行的时候清理掉引用次数为 0 的值占用的内存。
但其有一个致命问题就是循环引用会引发内容泄漏

function problem() {
    var objA = new Object();
    var objB = new Object();
    objA.someObject = objB;
    objB.anotherObject = objA;
}

这个引用类型的一个值又指向了另一个引用类型,这样,每个引用类型的引用次数都是2,且在引用类型之间形成了循环引用,这样,即使problem()函数执行完毕,把后期不再使用的局部变量objA和objB释放,但是因为引用类型的引用次数还是1,那么这两个引用类型还是不能被释放的,这就造成了内存泄露。
解决方法:手动切断引用

objA = null;
objB = null;

 

内存泄漏

1.闭包

由于IE的js对象和DOM对象使用不同的垃圾收集方法,因此闭包在IE中会导致内存泄露问题,也就是无法销毁驻留在内存中的元素。
闭包可以维持函数内部变量驻留内存,使其得不到释放

function(){
 var oDiv = document.getElementById('oDiv');//oDiv用完之后一直驻留在内存中
    oDiv.onclick = function () {
        alert('oDiv.innerHTML');//这里用oDiv导致内存泄露
    };
  }

其无意间将变量oDiv泄漏到内存中,最简单的方法就是手动解除引用,或定义在函数外面。

oDiv = null;

 

2.全局变量

声明过多的全局变量,会导致变量常驻内存,要直到进程结束才能够释放内存。

 

3.无效的DOM引用

<div id="btn_container">
        <button id="btn">demo</button>
</div>
var g = function(id){return document.getElementById(id);}
        g('btn').onclick=function(){
            g('btn_container').innerHTML = "触发了事件!";
        }

这时点击btn时,就会触发事件处理把btn按钮给覆盖,但是其click事件没有被清除,就会泄露到内存中,当然可以将其设为null
g(‘btn’).οnclick=null;我们也可以使用更好的方法,事件委托来处理这类问题。

g('btn_container').onclick=function(e){
   //获取触发事件
   var target = e && e.target || window.event.srcElement;
   //判断触发事件元素id是否为btn
   if(target.id==='btn'){
      //重置父元素内容
      g('btn_container').innerHTML = '触发了事件';
   }
}

 

4.被遗忘的计时器或回调函数

var someResource = getData();
setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
        // 处理 node 和 someResource
        node.innerHTML = JSON.stringify(someResource));
    }
}, 1000);

5.缓存

JS 开发者喜欢用对象的键值对来缓存函数的计算结果,但是缓存中存储的键越多,长期存活的对象也就越多,这将导致垃圾回收在进行扫描和整理时,对这些对象做无用功。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值