JavaScript的垃圾回收机制

JavaScript具有自动垃圾回收机制,也就是说,执行环境会负责管理代码执行过程中使用的内存。在编写JavaScript程序时,开发人员不必再关心内存使用问题,所需内存的分配以及无用内存的回收完全实现了自动管理。

原理--找出那些不再继续使用的变量,然后释放其占用的内存。这一过程不是实时的(因为其开销比较大),所以,JavaScript垃圾收集器会按照固定的时间间隔(或代码执行中预定的收集时间),周期性的执行这一操作,。

函数中局部变量的正常周期

不再使用的变量也就是声明周期结束的变量,当然只能是局部变量,因为全局变量的生命周期直至浏览器关闭才结束。

局部变量只在函数执行的过程中存在。而在这个过程中,会为局部变量在栈(或堆)内存上分配相应的空间,以便储存它们的值。然后在函数中使用这些变量,直至函数执行结束。此时,局部变量就没有存在的必要了,因此可以释放它们的内存以供将来使用。在这种情况下,很容易判断变量是否还有存在的必要;但并不是所有情况下都能这么容易的得到结论。垃圾收集器必须跟踪哪个变量有用哪个变量没有用,对于不再有用的变量打上标记,以备将来收回其占用的内存。

用于标识无用变量的策略可能会因实现而异,但具体到浏览器中的实现,通常有两个策略。

  • 标记清除

       原理--当变量进入环境(如在函数中声明一个变量)时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占用的内存,因为只要执行流进入相应的环境,就可能会用到它们。而当变量离开环境时,则将其标记为''离开环境"。

      可以使用任何方式来标记变量。比如,可以通过翻转某个特殊的位来记录一个变量何时进入环境,或者使用一个“进入环境的”变量列表及一个“离开环境的”变量列表来跟踪哪个变量发生了变化。

      工作流程-->

              1.垃圾收集器在运行的时候会给存储在内存中的所有变量加上都加上标记(可以使用任何标记方式)。

              2.然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记。

              3.而在此后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。

              4.最后,垃圾收集器完成内存清除工作,销毁那些带标记的值并回收它们所占用的内存空间。

  • 引用计数

       原理--跟踪记录每个值被引用的次数。

       工作流程-->

              1.当声明了一个变量并将一个引用类型的值赋给该变量时,这个值的引用次数就是1;

              2.如果同一个值又被赋给另外一个变量,则该值的引用次数加1;

              3.相反,如果包含对这个值的引用的变量又取得了另外一个值,则这个值的引用次数减1;

              4.当这个值的引用次数变为0时,则说明没有办法再访问这个值了,因而就可以将其占用的内存空间回收;

              5.当垃圾收集器下次再运行时,它就会释放那些引用次数为0的值所占用的内存。

    function problem () {
        var objectA=new Object();
        var objectB=new Object();

        objectA.someOtherObject =objectB;
        objectB.anotherObject=objectA;
    }

在这个例子中,objectA和objectB通过各自的属性相互引用,可以看出这两个对象的引用次数都是2.

在标记清除策略中,由于函数执行后,这两个对象都离开了作用域,因此这种相互引用不是个问题。

但在引用计数策略中,当函数执行完毕,两个对象因为引用次数不为0,所以还将继续存在。加入这个函数被重复多次调用,就会导致大量内存得不到回收。所以一般采用标记清除策略。但引用计数导致的麻烦并未就此中介。

在IE中有一部分对象并不是原生JavaScript对象。例如,其BOM和DOM中的对象就是使用C++以COM对象的形式实现的。而COM对象的垃圾回收机制采用的就是引用计数策略。因此,即使IE的JavaScript引擎是采用标记清除策略来实现的,但JavaScript访问的COM对象依然是基于引用计数策略的。换句话说,只要在IE中涉及COM对象,就会存在循环引用问题。

    var element=document.getElementById("some_element");
    var myObject = new Object();
    myObject.element = element;
    element.someObject = myObject;

上面这个例子在DOM元素(element)与一个原生JavaScript对象(myObject)之间创建了循环引用。其中,变量myObject 有一个名为element的属性指向element对象。而变量element也有一个属性名为 someObject的属性指向myObject。由于存在这个循环引用,即使将例子中的DOM 元素从页面中移除,它也永远不会消失。

为了避免类似这样的循环引用问题, 最好是在不使用它们的时候手工断开原生JavaScript对象与DOM元素之间的连接。例如可以使用下面的代码消除前面例子创建的循环引用。

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

将变量值设为null意味着切断变量与它此前引用的值之间的连接。当下次回收机制运行时候,就会删除这些值并回收它们占用的内存。

总结--一旦数据不再有用,最好通过将其值设为null来释放其引用,这叫做解除引用,适用于大多数全局变量和全局对象的属性,局部变量会在它们离开执行环境时自动被解除引用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值