持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
JS内存泄露如何检测?场景有哪些?
这个问题大部分同学可能没怎么接触过,因为这种情况在实际场景中比较少会遇到,但是也只是相对少而已,在越复杂的系统中出现的概率越高。解决这个问题不能直接来,要一步一步来! 由浅到深!
1.垃圾回收GC
- 什么是垃圾回收?
- JS是如何进行垃圾回收的?
什么是垃圾回收?
先看一个例子:
function fn1() {
const a = 'aa'
const obj = {x :100}
}
fn1()
这里先抛出一个简单的问题:执行完毕 fn 之后,a、obj 这两个常量还在吗?
答案肯定是不存在的。这不是显而易见吗!
函数执行完毕之后,函数中定义的变量和内存中占用的空间就被回收了,这就是所谓的垃圾回收。垃圾回收这是 JS引擎需要做的事情,但是有的浏览器的JS引擎并不是完全及时的。
如果我们的代码都是这样的,那是不会造成内存泄露的,那么是什么情况会导致垃圾无法回收呢?
再看一个例子:
function fn2() {
const obj = {x :100}
window.obj = obj // 垃圾 ???
}
fn2()
console.log(window.obj)
- 如果执行完毕
fn2
之后{x :100}
还会有吗?- 答案是:有; 因为
window.obj
已经引用了{x :100}
2.window.obj
是垃圾吗? - 不是垃圾,因为我们需要保存这个数据,是符合用户预期的
- 但是他表现出了一个情况:有些数据被外部引用,而不能被浏览器及时的进行回收
- 答案是:有; 因为
再再看一个例子:
function getDataFns() {
const data = {}
return {
get(key) {
return data[key]
},
set(key, value) {
data[key] = value
}
}
}
const { get, set } = getDataFns()
set('x', 100)
get('x')
这上面就是一个简单的闭包,我们在不断 set 的时候,会不断往 data 中填充数据,但是 data 并不会被清理。
小结
这里我们举了几种例子:
- 普通函数中的变量可以被正常进行回收
- 被外部引用到的,不能进行回收
- 闭包中的也不能进行回收
我们先抛开后面的两种情况,我们根据第一个情况看看 JS是如何进行垃圾回收的?
JS是如何进行垃圾回收的?
这里有兴趣可以看看我之前的文章:
JS中的垃圾回收算法
- 引用计数算法
- 通过设置引用计算器来维护当前对象的引用数,从而判断当前引用数是否为0,来决定是否垃圾对象,如果为0的情况下,启动GC来进行垃圾回收
- 引用计数算法
- 引用计数算法优缺点介绍
- 标记清除算法
- 标记清除算法是一种直接的全面停顿算法。简单的说,它们找出所有不可达的对象,并将它们放入空闲列表Free。
- JS性能优化之标记清除算法
曾经非常经典的内存泄露
在 IE6-IE7中
var div1 = document.getElementById('div1')
div.a = div1
div1.someBigData = {
//内存占用很大的数据
}
这样就会导致内存泄露,内存泄露是一些非预期的垃圾回收不了。预期的,比如闭包等就不算是内存泄露了。