内存泄漏指的是由于疏忽或者错误未能释放已经不再使用的内存
JavaScript有自己的垃圾回收机制,
执行环境会负责管理代码执行过程中使用的内存。
通常有以下两种方式
-
标记清除
-
引用计数
标记清除
当变量进入执行环境时,就标记这个变量为“进入环境”,进入环境的变量占用的内存就不能释放,当变量离开环境时,就标记为“离开环境”。
标记阶段
垃圾回收机制运行的时候,会给所有可访问的对象做上标记,通常是通过给对象添加一个标记位或者在其上创建一个引用链来实现。
清除阶段
标记阶段完成后,那些未被标记的对象就被视为不可访问的,垃圾回收器会将其所占的内存释放掉,以供后续使用。
引用计数
JavaScript引擎有一张引用表,保存了内存里面所有的资源的引用次数,如果一个资源的引用次数为0,就表示这个值不会再用到了,因此会将这块内存释放。
如果一个值不再需要了,引用数却不为0
,垃圾回收机制无法释放这块内存,从而导致内存泄漏
const arr = [1, 2, 3, 4]; console.log('hello world');
数组[1, 2, 3, 4]
是一个值,会占用内存。变量arr
是仅有的对这个值的引用,因此引用次数为1
。尽管后面的代码没有用到arr
,它还是会持续占用内存
如果需要这块内存被垃圾回收机制释放,只需要设置如下:
arr = null
此时就会被垃圾回收器回收了。
常见内存泄漏情况
-
意外全局变量
function foo(arg) { bar = "this is a hidden global variable"; }
上述bar忘记用let或const声明,变成了全局变量。
-
定时器未清理
当使用setTimeout()或者setInterval()创建定时器时,如果没有即使清除,那么定时器仍旧保留着堆函数的引用,即使执行完毕仍不会被垃圾回收机制回收
-
循环引用
var a = {}; var b = {}; a.b = b; b.a = a;