JavaScript
代码运行时, 需要分配内存空间来储存变量和值。当变量不在参与运行时, 就需要系统收回被占用的内存空间, 这就是垃圾回收。
Javascript
具有自动垃圾回收机制, 会定期对那些不再使用的变量、对象所占用的内存进行释放, 原理就是找到不再使用的变量, 然后释放掉其占用的内存。JavaScript
中存在两种变量: 局部变量和全局变量。全局变量的生命周期会持续要页面卸载; 而局部变量声明在函数中, 它的生命周期从函数执行开始, 直到函数执行结束, 在这个过程中, 局部变量会在堆或栈中存储它们的值, 当函数执行结束后, 这些局部变量不再被使用, 它们所占有的空间就会被释放。浏览器通常使用的垃圾回收方法有两种: 标记清除, 引用计数。
标记清除是浏览器常见的垃圾回收方式, 当变量进入执行环境时, 就标记这个变量“进入环境”, 被标记为“进入环境”的变量是不能被回收的, 因为他们正在被使用。当变量离开环境时, 就会被标记为“离开环境”, 会被 ……
标记被内存释放。
垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后, 它会去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量, 原因是环境中的变量已经无法访问到这些变量了。最后。垃圾收集器完成内存清除工作, 销毁那些带标记的值, 并回收他们所占用的内存空间。
另外一种垃圾回收机制就是引用计数, 这个用的相对较少。引用计数就是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时, 则这个值的引用次数就是 1
。相反, 如果包含对这个值引用的变量又取得了另外一个值, 则这个值的引用次数就减 1
。当这个引用次数变为 0
时, 说明这个变量已经没有价值, 因此, 在在机回收期下次再运行时, 这个变量所占有的内存空间就会被释放出来。
这种方法会引起循环引用的问题: 例如: obj1
和 obj2
通过属性进行相互引用, 两个对象的引用次数都是 2
。当使用循环计数时, 由于函数执行完后, 两个对象都离开作用域, 函数执行结束, obj1
和obj2
还将会继续存在, 因此它们的引用次数永远不会是 0
, 就会引起循环引用。
function fun() {
let obj1 = {};
let obj2 = {};
obj1.a = obj2; // obj1 引用 obj2
obj2.a = obj1; // obj2 引用 obj1
}
这种情况下, 就要手动释放变量占用的内存:
obj1.a = null
obj2.a = null
虽然浏览器可以进行垃圾自动回收, 但是当代码比较复杂时, 垃圾回收所带来的代价比较大, 所以应该尽量减少垃圾回收。
[ ]
, 但是与此同时会创建一个新的空对象, 可以将数组的长度设置为 0
, 以此来达到清空数组的目的。object
进行优化: 对象尽量复用, 对于不再使用的对象, 就将其设置为 null
, 尽快被回收。以下四种情况会造成内存的泄漏:
setInterval
定时器, 而忘记取消它, 如果循环函数有对外部变量的引用的话, 那么这个变量会被一直留在内存中, 而无法被回收。DOM
的引用: 获取一个 DOM
元素的引用, 而后面这个元素被删除, 由于一直保留了对这个元素的引用, 所以它也无法被回收。