javascript垃圾回收和内存泄漏

垃圾回收机制
当我们用js代码创建一个引用类型的时候,js引擎会在内存中开辟一块空间来存放数据,并把指针引用交给那个变量。内存是有限的,js引擎必须保证当这个对象没用的时候,把所分配的内存空间释放出来,这个过程叫做垃圾回收。
JS中的垃圾回收机制,有两种策略来实现垃圾回收:标记清除 和 引用计数;

标记清除:垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记,然后,它会去掉环境中的变量的标记和被环境中的变量引用的变量的标记,此后,如果变量再被标记则表示此变量准备被删除。 2008年为止,IE,Firefox,opera,chrome,Safari的javascript都用使用了该方式;

引用计数:跟踪记录每个值被引用的次数,当声明一个变量并将一个引用类型的值赋给该变量时,这个值的引用次数就是1,如果这个值再被赋值给另一个变量,则引用次数加1。相反,如果一个变量脱离了该值的引用,则该值引用次数减1,当次数为0时,就会等待垃圾收集器的回收。

这个方式存在一个比较大的问题就是循环引用。看下面这个例子
循环引用的问题

function problem(){
    var objectA= new objece();
    var objectB= new objece();
    objectA.sonmeOtherObject=objectB;
    objectB.anotherObject=objectA;
}   

就是说A对象包含一个指向B的指针,对象B也包含一个指向A的引用。 在采用标记清除策略的实现中,由于函数执行后,这两个对象都不离开了作用域,因此这种相互引用不是问题。但在采用引用计数回收机制的js引擎中,这就可能造成大量内存得不到回收,(即内存泄露,为什么说可能?且看后文)因为它们的引用次数永远不可能是 0 ,内存泄露的一个原因就是这个算法的一个缺陷。
而不是闭包的问题!!

内存泄露
现在大部分的js引擎已经放弃使用引用计数回收机制,避免了上面的内存泄漏问题,像第一段代码objectA和objectB的循环引用,不会导致内存泄漏,因为两个都是js原生对象,所有js引擎都会采用标记清除实现回收。但是IE又有一个特殊的地方。IE9之前版本中,有一部分对象并不是原生额javascript对象,例如,BOM和DOM中的对象就是以COM对象的形式实现的,而COM对象的垃圾回收机制采用的就是引用计数。因此,虽然IE的javascript引擎采用的是标记清除策略,但是访问COM对象依然是基于引用计数的,因此只要在IE中设计COM对象存在循环引用就会导致内存泄漏,举个例子:

var element = document.getElementById("id");
var myObject= new objece();
myObject.element =element;
element.someObject=myObject;

这个例子在DOM元素和原生js对象中建立了循环引用,在ie9之前版本会内存泄漏,因为在这些引擎中,两种对象采用不同的内存管理,element 对象采用引用计数,它的引用数始终至少为1,无法回收。即使dom对象在某个时刻被移除掉了,但js引擎不知道它被移除掉,还傻傻的保留着引用呢,就不会把js对象释放。
解决的办法是切断彼此之间的引用:

myObject.element =null;
element.someObject=null;

所以,闭包不是真正产生内存泄漏的原因!
下面这个例子:
function assignHandler() {
var element = document.getElementById("someElement");
element.onclick = function() {
alert(element.id);
}
}

这个闭包函数和dom对象循环引用,在早期ie,element 对象无法回收,会内存泄漏,引擎控制不住。

function assignHandler() {
    var element = {id:123};
    element.onclick = function() {
        alert(element.id);
    }
}

这个闭包就不存在内存泄漏了,因为js引擎控制好了内存管理问题。有些人可能会疑惑,闭包不是引用着外函数变量对象吗,那内存中不就一直存在这些变量对象?这个没错,闭包会产生内存占用,但这不是内存泄漏,这正是我们使用闭包的目的,我们使用闭包就是要保存这些内部变量的状态,以便我们任何时候去通过闭包使用它作用域内的变量。它不是内存泄漏,因为资源还可需引用,尚无需回收,直到闭包被销毁了,才一起被回收。

总结:内存泄漏是一些js引擎采用引用计数垃圾回收算法导致的问题,与闭包无关。
闭包确实是在保持对别的对象的引用,也会产生较大的内存占用,但是,它不是内存泄漏,是闭包的特点

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值