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 。