一、为什么要垃圾回收
如果没有垃圾回收机制,适时清理不被引用的值并释放相应的内存空间,JavaScript 解释器将会消耗完系统中所有可用内存,造成系统崩溃。
二、垃圾回收的核心思路
所谓垃圾回收的核心思想就是清理掉内存中不再被引用的值,通俗的说,就是清理掉内存中没用的值,那么如何判断有没有用?如果是局部变量,在函数调用结束后即是无用的,可以被回收掉;而全局变量在浏览器卸载页面的时候才会消失。由于这个过程消耗较大,所以解释器会按照固定时间周期性的执行回收。
三、垃圾回收的两种方式
1.标记清除(JS最常用)
标记清除法主要有以下三个步骤:
1)给所有变量增加一个标记,如果是进入执行环境(比如申明变量),则标记为“进入环境”,如果是结束执行环境(比如执行完相关函数),则标记为“离开环境”;
2)去掉“进入环境”的变量标记以及被该变量所引用的变量标记(比如闭包);
3)还存在标记的变量即是需要被清理的变量。
2.引用计数
引用计数法主要有以下三个步骤:
1)申明了一个变量,并且将一个引用类型的值赋值给这个变量,那么这变量的引用就加1;
2)如果这个变量的值又指向另外一个值,或者说这个变量被重新赋值了,那么以上的引用类型的值的引用次数就减1;
3)如此一来,该引用类型的值的引用次数即为0,垃圾回收器会在运行的时候清理掉引用次数为0的值并释放相应的内存空间;
4)特别注意:引用计数在代码中存在循环引用时会出现问题
四:附4常见的内存泄漏问题
1.意外声明全局变量
function setName(){
name = 'Jake';
}
此时变量name会被当做window的属性,即全局对象来处理,只要window本身不被清理就不会消失。
2.定时器也可能会悄悄地导致内存泄露
let name = 'Jake';
setInterval(()=>{
consolog.log(name);
},100)
只要定时器一直运行,回调函数中引用的name就会一直占用内存。
3.使用闭包也很容易造成内存泄漏
let outer = function(){
let name = 'Jake';
return function(){
return name;
}
}
内部闭包只要outer函数存在就不能清理name。