JavaScript垃圾回收机制

1.首先要明确什么是垃圾?

在JS中认定一样东西是垃圾的几种方法(一般认为没有被引用的就是垃圾):

  • 所有全局变量都不是垃圾
  • 局部变量在这个函数执行完之后就变成了垃圾
  • 如果存在双引用,删了其中一个对象还是不会变成垃圾的,因为还有另外一个对象在引用它
    双引用
  • 环引用(别人引用你才有用,你引用别人是没有用的,对外界至少有一个桥梁,不要成为孤岛)
    环引用

2.垃圾回收的必要性

由于字符串、对象和数组没有固定大小,所有当他们的大小已知时,才能对他们进行动态的存储分配。JavaScript程序每次创建字符串、数组或对象时,解释器都必须分配内存来存储那个实体。只要像这样动态地分配了内存,最终都要释放这些内存以便他们能够被再用,否则,JavaScript的解释器将会消耗完系统中所有可用的内存,造成系统崩溃。
引自《JavaScript权威指南(第四版)》

3.浏览器是如何找到这些垃圾并且被回收的?

  1. 标记-清除算法
    步骤:
  • 垃圾回收器获取根并“标记”(记住)它们。
  • 然后它访问并“标记”所有来自它们的引用。
  • 然后它访问标记的对象并标记它们的引用。所有被访问的对象都被记住,以便以后不再访问同一个对象两次。
  • 以此类推,直到有未访问的引用(可以从根访问)为止。
  • 除标记的对象外,所有对象都被删除。
    标记-清除算法

    缺点:JS是单线程的,在标记过程中,JS不能执行,如果有人把标记的删了,JS怎么解决?
    改进方法:

  • 新生代和老一代(垃圾回收的时间不一样)
  • 增量收集(例如:先收集1000个不中断,执行JS,然后继续收集一定的个数)
  • 空闲时间收集
  1. 引用计数算法
      记录每个对象被引用的次数,每次新建对象、赋值引用和删除引用的同时更新计数器,如果计数器值为0则直接回收内存。 很明显,引用计数最大的优势是暂停时间短
    优点
  • 可即刻回收垃圾
  • 最大暂停时间短
  • 没有必要沿指针查找,不要和标记-清除算法一样沿着根集合开始查找
    缺点
  • 计数器的增减处理繁重
  • 计数器需要占用很多位
  • 实现繁琐复杂, 每个赋值操作都得替换成引用更新操作
  • 循环引用无法回收

4.前端还有特殊性(不仅有JS进程,还有DOM进程)

在浏览器里面,所有全局变量都没有引用也不代表这个东西就可以删除,因为有可能dom元素引用了这个函数
DOM元素引用

本文参考链接:
https://segmentfault.com/a/1190000018605776?utm_source=tag-newest
https://www.jianshu.com/p/a8a04fd00c3c

你可能感兴趣的:(JavaScript垃圾回收机制)