JavaScript 垃圾回收机制分析

 更新时间:2013年10月13日 07:27  点击:2786

在公司经常会听到大牛们讨论时说道内存泄露神马的,每每都惊羡不已,最近精力主要用在了Web 开发上,读了一下《JavaScript高级程序设计》(书名很唬人,实际作者写的特别好,由浅入深)了解了一下JavaScript垃圾回收机制,对内存泄露有了一定的认识。

和C#、Java一样JavaScript有自动垃圾回收机制,也就是说执行环境会负责管理代码执行过程中使用的内存,在开发过程中就无需考虑内存分配及无用内存的回收问题了。JavaScript垃圾回收的机制很简单:找出不再使用的变量,然后释放掉其占用的内存,但是这个过程不是时时的,因为其开销比较大,所以垃圾回收器会按照固定的时间间隔周期性的执行。

变量生命周期

有同学看了上面就会问了,什么叫不再使用的变量?不再使用的变量也就是生命周期结束的变量,当然只可能是局部变量,全局变量的生命周期直至浏览器卸载页面才会结束。局部变量只在函数的执行过程中存在,而在这个过程中会为局部变量在栈或堆上分配相应的空间,以存储它们的值,然后再函数中使用这些变量,直至函数结束(闭包中由于内部函数的原因,外部函数并不能算是结束,了解闭包可以看看 JavaScript作用域链,JavaScript 闭包究竟是什么)。

一旦函数结束,局部变量就没有存在必要了,可以释放它们占用的内存。猫和很简单的工作,为什么会有很大开销呢?这仅仅是垃圾回收的冰山一角,就像刚刚提到的闭包,貌似函数结束了,其实还没有,垃圾回收器必须那个变量游泳,那个变量没用,对于不再有用的变量打上标记,以备将来回收。用于标记无用的策略有很多,常见的有两种方式

标记清除(mark and sweep)

这是JavaScript最常见的垃圾回收方式,当变量进入执行环境的时候,比如函数中声明一个变量,垃圾回收器将其标记为“进入环境”,当变量离开环境的时候(函数执行结束)将其标记为“离开环境”。至于怎么标记有很多种方式,比如特殊位的反转、维护一个列表等,这些并不重要,重要的是使用什么策略,原则上讲不能够释放进入环境的变量所占的内存,它们随时可能会被调用的到。

垃圾回收器会在运行的时候给存储在内存中的所有变量加上标记,然后去掉环境中的变量以及被环境中变量所引用的变量(闭包),在这些完成之后仍存在标记的就是要删除的变量了,因为环境中的变量已经无法访问到这些变量了,然后垃圾回收器相会这些带有标记的变量机器所占空间。

大部分浏览器都是使用这种方式进行垃圾回收,区别在于如何标记及垃圾回收间隔而已,只有低版本IE,不出所料,又是IE。。。

引用计数(reference counting)

在低版本IE中经常会出现内存泄露,很多时候就是因为其采用引用计数方式进行垃圾回收。引用计数的策略是跟踪记录每个值被使用的次数,当声明了一个变量并将一个引用类型赋值给该变量的时候这个值的引用次数就加1,如果该变量的值变成了另外一个,则这个值得引用次数减1,当这个值的引用次数变为0的时候,说明没有变量在使用,这个值没法被访问了,因此可以将其占用的空间回收,这样垃圾回收器会在运行的时候清理掉引用次数为0的值占用的空间。

看起来也不错的方式,为什么很少有浏览器采用,还会带来内存泄露问题呢?主要是因为这种方式没办法解决循环引用问题。比如对象A有一个属性指向对象B,而对象B也有有一个属性指向对象A,这样相互引用

代码如下:


function test(){
            var a={};
            var b={};
            a.prop=b;
            b.prop=a;
        }

这样a和b的引用次数都是2,即使在test()执行完成后,两个对象都已经离开环境,在标记清除的策略下是没有问题的,离开环境的就被清除,但是在引用计数策略下不行,因为这两个对象的引用次数仍然是2,不会变成0,所以其占用空间不会被清理,如果这个函数被多次调用,这样就会不断地有空间不会被回收,造成内存泄露。

在IE中虽然JavaScript对象通过标记清除的方式进行垃圾回收,但BOM与DOM对象却是通过引用计数回收垃圾的,也就是说只要涉及BOM及DOM就会出现循环引用问题。看上面的例子,有同学回觉得太弱了,谁会做这样无聊的事情,其实我们是不是就在做

代码如下:


window.onload=function outerFunction(){
        var obj = document.getElementById("element");
        obj.onclick=function innerFunction(){};
    };

这段代码看起来没什么问题,但是obj引用了document.getElementById("element"),而document.getElementById("element")的onclick方法会引用外部环境中德变量,自然也包括obj,是不是很隐蔽啊。

解决办法

最简单的方式就是自己手工解除循环引用,比如刚才的函数可以这样

代码如下:


window.onload=function outerFunction(){
        var obj = document.getElementById("element");
        obj.onclick=function innerFunction(){};
       obj=null;
    };

什么时候触发垃圾回收

垃圾回收器周期性运行,如果分配的内存非常多,那么回收工作也会很艰巨,确定垃圾回收时间间隔就变成了一个值得思考的问题。IE6的垃圾回收是根据内存分配量运行的,当环境中存在256个变量、4096个对象、64k的字符串任意一种情况的时候就会触发垃圾回收器工作,看起来很科学,不用按一段时间就调用一次,有时候会没必要,这样按需调用不是很好吗?但是如果环境中就是有这么多变量等一直存在,现在脚本如此复杂,很正常,那么结果就是垃圾回收器一直在工作,这样浏览器就没法儿玩儿了。

微软在IE7中做了调整,触发条件不再是固定的,而是动态修改的,初始值和IE6相同,如果垃圾回收器回收的内存分配量低于程序占用内存的15%,说明大部分内存不可被回收,设的垃圾回收触发条件过于敏感,这时候把临街条件翻倍,如果回收的内存高于85%,说明大部分内存早就该清理了,这时候把触发条件置回。这样就使垃圾回收工作职能了很多。

同C# 、Java一样我们可以手工调用垃圾回收程序,但是由于其消耗大量资源,而且我们手工调用的不会比浏览器判断的准确,所以不推荐手工调用垃圾回收。

[!--infotagslink--]

相关文章

  • JavaScript 垃圾回收机制分析

    在公司经常会听到大牛们讨论时说道内存泄露神马的,每每都惊羡不已,最近精力主要用在了Web 开发上,读了一下《JavaScript高级程序设计》(书名很唬人,实际作者写的特别好,由浅入深)了解了一下JavaScript垃圾回收机制,对内存泄露...2013-10-13
  • Python析构函数__del__定义原理解析

    这篇文章主要介绍了Python析构函数__del__定义原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-11-20
  • 一篇文章带你了解JVM垃圾回收

    这篇文章主要介绍了JVM的种垃圾回收,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-08-15
  • python垃圾回收机制(GC)原理解析

    这篇文章主要介绍了python垃圾回收机制(GC)原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下...2020-05-08
  • C# 的析构以及垃圾回收实例分析

    这篇文章主要介绍了C# 的析构以及垃圾回收实例分析的相关资料,需要的朋友可以参考下...2020-06-25
  • apache下屏蔽福建莆田的垃圾评论并阻止访问

    2014年开年,我的小网站就被来自福建莆田的大量垃圾IP地址疯狂的刷站,每分钟几十次的流量,写入大量垃圾评论。查了一下网上的消息,很多小博客和论坛都被狂刷,而且都是来自福建莆田...2016-01-28
  • 浅谈MySQL表空间回收的正确姿势

    随着时间的推移,表里面的数据越来越多,表数据文件越来越大,数据库占用的空间自然也逐渐增长,本文主要介绍了MySQL表空间回收,感兴趣的可以了解一下...2021-09-29
  • 详解PHP垃圾回收机制教程

    本文我们来详谈PHP垃圾回收机制,本教程是在PHP 5.3的新垃圾回收机制的特点,这种垃圾回收机制,大大改变内存泄漏问题难以解决的问题。 这部分将说明PHP 5.3的新的垃圾...2016-11-25
  • PHP垃圾回收机制详解

    PHP 可以自动进行内存管理,清除不再需要的对象。PHP使用了引用计数(reference counting)这种单纯的垃圾回收(garbage collection)机制。每个对象都内含一个引用计数器,...2016-11-25
  • PHP线程的内存回收问题

    本文给大家介绍的是PHP线程的内存回收问题,方便大家理解内存回收的机制,推荐给大家。...2016-07-25
  • IIS 6.0 应用程序池回收和工作进程使用介绍

    这篇文章主要介绍了IIS 6.0 应用程序池回收和工作进程介绍,需要的朋友可以参考下...2016-01-27
  • .net非托管资源的回收方法

    这篇文章主要介绍了.net非托管资源的回收方法,以实例形式详细分析归纳了.net非托管资源的两种回收方法,具有一定的参考借鉴价值,需要的朋友可以参考下...2021-09-22
  • Go语言七篇入门教程七GC垃圾回收三色标记

    这篇文章主要为大家介绍了Go语言教程关于GC垃圾回收三色标记的示例详解,本篇文章是Go语言七篇入门教程系列文章,有需要的朋友可以借鉴参考下,希望能够有所帮助...2021-11-10
  • .Net  垃圾回收机制详细介绍

    这篇文章主要介绍了.Net 垃圾回收机制详细介绍的相关资料,这里对垃圾回收机制做了详细的讲解,需要的朋友可以参考下...2021-09-22
  • go:垃圾回收GC触发条件详解

    这篇文章主要介绍了go:垃圾回收GC触发条件详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-04-24
  • python对象销毁实例(垃圾回收)

    今天小编就为大家分享一篇python对象销毁实例(垃圾回收),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-04-27
  • C#的内存回收代码

    这篇文章主要介绍了C#的内存回收代码,涉及到win32底层操作,具有一定的参考学习价值,需要的朋友可以参考下...2020-06-25
  • 收到垃圾短信千万不要按照提示退订 教你一招即可屏蔽

    不要相信垃圾广告短信说的回TD或者回N退订,你回了,只能让它确认这个手机号是有人在用的,以后会变本加厉地发,甚至卖给别的广告商。原来短信内容中的“回复T即可退订”完全是糊弄人的,只有回复“复T即可”才是正确的退订方式。不得不感叹一些广告商的智慧真是无穷的...2016-12-21
  • 浅谈JVM垃圾回收之哪些对象可以被回收

    这篇文章主要介绍了JVM垃圾回收之哪些对象可以被回收,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-03-19
  • IIS6.0应用程序池回收设置分析

    这段时间公司的程序经常出现问题,然后整个应用程序就不能访问了,我们的服务器版本:window 2003 SP1,IIS6.0,没有安装Microsoft Visual Studio .NET...2016-01-27