JavaScript - 垃圾回收机制GC - 小四@王云飞

function sf() {
    var num = 0
    return function inner() {
      console.log(num)
    }
    inner()
  }

  var fn = sf()
  fn()
  fn()
  fn()

把一个内部的函数,通过return的形式,拿到了全局范围,然后就变成了全局函数。本来num是一个局部变量,本来它被用完了应该被清理,但是现在不清理,这个num变量会一直存在,一直到全部的调用都消失了,才会清理。

这种情况就涉及到了垃圾回收机制的问题

画图说明更直观:

垃圾回收机制 - 王云飞

去餐厅吃饭,吃完饭餐桌肯定弄的乱七八糟。
一种情况是按照要求,所有吃完饭的人,走之前你必须给我把桌子给我收拾干净,不然不能走。
另一种,你尽管吃,别管多乱,吃完你就走,旁边会有一个专门负责打扫卫生的保洁,然后他没事就在这里转悠,她发现这个桌子吃完了,然后清理掉。这个充当的就是垃圾回收器的角色。简称为GC。
很显然它是自动的不用你管我们的JS也是这样的,所以当一个变量没有用清理的时候你不必担心,该清理的时候自然就清理了。

垃圾回收机制的常见算法

引用计数法(浏览器):

用的较多
计数法的意思就是给每个变量贴标签,只要有一个人用我就给他写个数字:1,两个人用我就写:2,三个人用就是:3;其中有一个人不用了我可以把技术撤掉,把3改回2。总之就是上面有个数字,代表几个人在使用。
这对于GC来说就简单了,它巡视查看内存的时候只要看这个变量的计数是不是等于0,如果等于0毫不犹豫的清理掉,不等于0说明还有人在使用就不能清理。
这种方式容易产生很多碎片,有些空间能用有些被占用了,不会连续,我们说硬盘里时不时要做碎片整理,就是为了让我们硬盘空间利用效率更高,所以说最好就是时不时的把空间规整一下,排个序。

复制整理法(Java内存管理):

不停在用,整个过程都不清理。一口气把所有的已经占用对的空间复制一遍,它在整个复制的过程中把所有的内存扫描了一遍,复制的时候把没用的清理了,而且做了重新排序。
缺点:你的内存必须得一分为二,可能有一半空间不能利用。如果你内存大不在乎,这种方式是不错的选择

标记清除法(浏览器):

用的不多
不停的增加,每隔一段时间就使劲的扫描内存,并且清理,过一段时间再扫描,和引用计数法一样,同样会存在碎片

标记整理法(浏览器):

用的较多
当变量越来越多的时候,它也会定期的进行扫描,扫描完了它从头到尾做了一个排序,一边清除,一边排序,工作量蛮大的

闭包中的变量num为什么不会被回收?

明白了垃圾回收机制,那么闭包中的num为什么不会被回收,应该就可以解释了吧!外面的全局函数还在使用num,因此num身上有计数,不为零,所以它不会被清除。

内存泄漏常见情况

  • 闭包写多了就会造成内存泄漏,一般不可能代码里全是闭包,我们只能说有这个风险
  • 大量的使用全局变量,现在基本不会出现,因为我们现在都模块化了,全局变量很少用
  • 定时器,这个可能性大一些,我们总是开启了就忘记了关闭,经常犯
  • DOM元素的引用:

  


解决方案

btn = null // 现在被释放了

大前端面试题库 - 2019.08.06

你可能感兴趣的:(JavaScript - 垃圾回收机制GC - 小四@王云飞)