最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 深入理解JavaScript垃圾回收

    正文概述 掘金(SwordQiu)   2021-02-19   459

    引言

    《JavaScript 高级程序设计第四版》关于垃圾回收,我个人认为关于标记清除写的是云里雾里的,直到我看到这篇文章,这里上英文版和中文版连接:

    Garbage collection

    中文版Garbage collection

    如果大家有兴趣可以读原文,我在这里用我的话描述一下并增加一些扩展内容。

    如有错误,感谢指正。??

    什么是垃圾

    首先我们需要先知道什么是垃圾。

    生活常识里什么是垃圾呢?

    现在以及未来都不再被需要的物体就是垃圾。程序里也是一样的道理。

    文章说了一个名词,叫做可达性。

    也就是说你不再能够访问到它的数据,就是不可达的。

    没有可达性的数据就可以被回收。

    这个逻辑很简单暴力,你都访问不到它了,确实没有要它的必要啊。

    毫无疑问,全局变量随时有可能被访问到,所以它是可达的,它不能是垃圾。

    其次,正在执行的函数,比如说这样的

    function fn(){
      var b=2
      console.log(b)
    }
    fn()
    

    当函数执行的时候,b的数据就会被生成,此时它是可达性的,不能被删除。

    然而当函数执行完后,它不能再被访问到,此时它是不可达的,需要删除。

    那么现在结论就是:

    • 全局环境下的变量因为都具有可达性,所以都不是垃圾不能被回收。

    • 局部环境下的变量因为不再具有可达性,所以都是垃圾可以被回收。

    但凡事都可以被改变。

    引用转移

    单个变量名引用转移

    // user 具有对这个对象的引用
    let user = {
      name: "John"
    };
    

    上面这段代码在内存中是这样的 深入理解JavaScript垃圾回收

    这是一个在全局环境下的变量,很有可能别的代码会用到它,所以不能被回收。

    但是,当 user 这个变量名引用变了

    user = null
    

    那原来的{name:John}这个数据就访问不到它了,此时就可以被回收。

    深入理解JavaScript垃圾回收

    但是如果代码是这样的

    let user = {
      name: "John"
    };
    let admin = user
    user = null
    

    此时{name:John}依然可以通过变量admin访问,它就不能被回收。

    相互关联的对象

    这里有一个更加复杂的对象

    function marry(man, woman) {
      woman.husband = man;
      man.wife = woman;
    
      return {
        father: man,
        mother: woman
      }
    }
    
    let family = marry({
      name: "John"
    }, {
      name: "Ann"
    });
    

    此时内存图是这样的 深入理解JavaScript垃圾回收

    如果此时执行这样的代码

    delete family.father;
    delete family.mother.husband;
    

    就会变成这样 深入理解JavaScript垃圾回收 此时 {name:John}不再可达,那么它就会被回收。

    深入理解JavaScript垃圾回收

    那么根据内存图,如果把family这个变量名引用到其他地方。

    family = null;
    

    很显然,原先的数据不再可达,它就会被回收。 深入理解JavaScript垃圾回收

    垃圾回收的策略

    上面是垃圾回收的基本概念,非常符合现实逻辑。

    下面是关于策略

    标记清理

    定期执行以下“垃圾回收”步骤,一开始数据是这样的 深入理解JavaScript垃圾回收

    1.垃圾收集器通过遍历找到所有的根,并“标记”(记住)它们。 深入理解JavaScript垃圾回收 2.如果还有引用的数据,说明是可达的。一直标记到最后一层引用。 深入理解JavaScript垃圾回收 3.此时发现有一个数据,从来没有被根(全局变量能访问到的)引用到,就把它回收掉。 深入理解JavaScript垃圾回收

    当然遍历的同时,因为数据量很大,为了不影响 JS 代码运行,加快垃圾回收速度,就做了一些优化处理(包括但不限于)

    • 分代收集

    通俗化就是把数据分为两种,新生代和旧生代。有些函数中的变量可以很快被垃圾回收掉,而长期没有被回收的变量,会从新的变成旧的,而且有可能永远不会被删除,所以就降低用垃圾回收检查它们的频次。----减少对某些数据定期遍历的次数

    • 增量收集

    慢慢收集,把垃圾回收的范围慢慢扩大而不是一次全部遍历完。----减少收集的范围,提高遍历的量次

    • 闲时收集

    这个非常通俗,让JS代码先走,闲下来的时候再去收集垃圾

    引用计数(扩展)

    这方面红宝书就写的比较清楚

    不过引用计数有非常大的问题:如果是互相引用,次数也会叠加

    function fn(){
      var a=1
      var b=a
    }
    fn()
    

    此时变量a会被记成2次引用,即使函数执行完了,a也不会被当成垃圾回收。

    闭包(扩展)

    注意到了吗,上面的例子没有讲到闭包,对于闭包我个人认为可以把它当成全局变量来看。

    以下摘自阮一峰的博客

    闭包的产生是因为一个函数被当前函数作用域外部的变量引用了,除非外部的变量被释放,否则闭包当然不会被回收。

    下面是例子:

    function f1(){
    
        var n=999;
    
        nAdd=function(){n+=1}
    
        function f2(){
          alert(n);
        }
    
        return f2;
    
      }
    
      var result=f1();//此时 result 相当于拿到了
    
      result(); // 999
    
      nAdd();
    
      result(); // 1000
    

    上面的数据n虽然在函数中,但是依然会存于内存中。

    如果nAddresult的引用没有被释放,那么数据n不会被垃圾回收。

    总结

    • 垃圾回收是自动完成的,我们不能强制执行或是阻止执行。
    • 当对象是可达状态时,它一定是存在于内存中的。
    • 被引用与可访问(从一个根)不同:一组相互连接的对象可能整体都不可达。

    最后??

    以上就是我对于垃圾回收的简单分享。

    如果您觉得对您有帮助,请顺手点个赞,谢谢!

    完结撒花!???


    起源地下载网 » 深入理解JavaScript垃圾回收

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元