js垃圾回收机制

# js垃圾回收机制

javascript中的内存管理是自动执行,不可见的。 我们创建基本类型、对象、函数都需要内存可达性 在js的垃圾回收机制中 可达性是主要的概念。 可达性的数据就是指那些以某种方式可访问或可用的值,他们被保证存储在内存中。 假设我们现在有这样一个数据

 var obj = {
    name:'zhangsan',
    age:18
 }

我们声明了一个变量obj,然后呢让obj引用了对象{name:'zhangsan',age:18} 这个时候 obj 存储的是对象的地址。 当我们 将 obj = null 清掉了obj对该对象的引用,这个时候 对象还是存在的对吧? obj也是存在的,只不过obj失去 了对{name:'zhangsan',age:18}的引用。 这个时候对象变成不可达的数据 将会被垃圾处理机制回收。

然后我们又假设在声明obj的同时声明了另外一个变量 abs ,我们让abs = obj,这个时候 obj这个变量保存的是对象的地址, 同时 abs保存的也是对象的地址。 abs、obj都指向对象{name:'zhangsan',age:18},这个时候我们让obj = null obj失去了 对象的引用 那这个时候 对象会被垃圾清除机制清理掉吗? 答案是不会的,因为abs还保留着对 该对象的引用 并非是不可达的。

 var obj = {
    name:'zhangsan',
    age:18
 }
 
 var abs = obj

有一组值无法被清除

  • 本地函数的变量和参数
  • 全局变量
  • 调用链上其他函数的变量和参数 这些被称为根(roots)

# 标记清除 - 算法机制

垃圾处理的算法机制是标记清除(mark-and-sweep),他定期的执行。

  • 首先垃圾处理器会标记所有的根
  • 然后会访问和标记所有来自根的引用
  • 访问所标记的对象并继续标记他们的引用,所有访问过的对象都会被标记,防止重复访问。
  • 依次反复的访问和标记所有可达引用
  • 所有没有被标记的对象将被清除回收。

js引擎通过优化使其运行的更快,不会影响正常代码的执行:

  • 分代回收:将对象分为“新对象”与“旧对象”。对新对象来讲,他会经常的被检测然后被清除。新对象经过多次的检测后会变为老对象,检测的次数会变少
  • 增量回收:一次性访问和标记整个对象显得很呆。因此,js引擎会试图将垃圾回收分解为多个部分,然后逐个击破。这需要额外的标记支持但是会响应的减小延迟。
  • 空闲时间回收:只在CPU空闲时运行,最大限度的减小对正常执行的影响。

# 引用计数

引用计数就是会跟踪并记录每个值的引用次数,值被引用,引用次数加一,反之减一,当引用次数为0时会被清除。 但是这个方式有一个缺陷就是无法处理重复引用的问题。造成内存泄漏。

  function handler(){
    var obj1 = {};
    var obj2 = {};
    obj1.value = obj2;
    obj2.value = obj1;
  }

当handler函数执行的时候 obj1 和 obj2 会重复的引用 这就造成他们的引用次数不会为0,这个时候只能手动释放引用。

# 可能会造成内存泄漏的情况:

  • 全局变量 - 全局变量运行时不会被回收,因此需要及时手动去清理,比如运用规范校验或者严格模式。
  • 闭包 - 闭包可以创建缓存值,不释放资源。
  • DOM 对象引用 - 如果某个DOM元素,在js中存在他的引用,他的生命周期时由js和是否在DOM树上两者决定的。
  • 定时器和回调 - 及时清理 setTimeout 和 setInterval 。