内存泄漏最终将导致页面反应迟缓,崩溃,高延迟
我们知道内存是有限的,比如8G,16G, 当我们创建了一些变量,其就会在内存中的对应位置 (堆栈的概念)
栈内存一般存储基础的数据类型(Number String Null undefined Boolean Symbol)
堆内存一般存储引用类型,包括对象Object和数组Array
但是我们如果一味的往里放,再大的内存都会放满,所以一些不用的变量就会被回收。
举个例子: 家里面的仓库再大,空间也有限,总不可能一直往里塞东西吧,哈哈哈。当仓库(内存)装满的时候,还要继续往里面装,就存在内存泄漏的问题。
为了让仓库能一直放,我们在打扫卫生的时候总会扔掉一些不要用的东西,在JS中也是一样,这叫做垃圾回收机制,向C语言中一般需要通过malloc申请内存资源,然后自己手动free来清除无用资源,而JS中是自动完成这一部分的。
引用计数 垃圾回收机制(GC)
和python一样,JS的垃圾回收机制为引用计数
当我们创建一个变量的同时,就相当于引用数为1,如果当一个变量无人引用引用数为0的时候,这个变量就会被删除。
所以我们现在知道一种内存泄漏的原因,有一些变量一直在被引用而导致内存无法被释放。
这里主要参考了这篇博文的内容:
参考博文
// example 1
function foo(arg) {
bar = "this is a hidden global variable";
}
// example 2
function foo() {
this.variable = "potential accidental global";
}
foo();
分析: 上述的bar 和this.variable 都是指向全局window,因此在这里相当于定义的是window.bar 和window.variable
因此在执行上述两段代码时,尽管函数执行完毕,本身其内部变量也应该随着函数的调用完毕而被回收,但实际是,由于在全局变量中被引用,并不会被垃圾回收,仍然存在!
setInterval只有在停止的时候,才会被回收,因此如果我们创建了很多setInterval而没有通过clearInterval()进行回收,就会使得每次创建的setInterval一直在内存中无法得到释放,(最终导致网页崩溃)
function test() {
console.log('123')
return setInterval(test, 10);
}
test()
如果有兴趣可以自己创一个网页试试看上述的例子,随着时间的增加,网页会崩溃,你可以通过任务管理器查询自己的内存消耗,会逐渐飙升,其原因就是没过10ms会创建一个setInterval且无法被回收
利用匿名函数来保存父级作用域内的变量,当闭包内保存着函数中的局部变量时,在函数调用完毕后,本应该被释放,但是由于闭包的存在导致函数中的变量也在被引用,所以函数仍没有被回收!(我的理解)
var theThing = null;
var replaceThing = function () {
var originalThing = theThing;
var unused = function () {
if (originalThing)
console.log("hi");
};
theThing = {
longStr: new Array(1000000).join('*'),
someMethod: function () {
console.log(someMessage);
}
};
};
setInterval(replaceThing, 1000);
借鉴了博文中的例子,在每个replaceThing的函数中都创建了一个theThing,这个theThing是独立保存的,且unused 和theThing 有关系,本来unused应该被回收,但是由于被循环引用,导致无法被回收造成内存的泄漏
F12 -> Performance ->勾选memory -> 点击原点
具体参考博文
Alon’s Blog
阮一峰老师的博文