JS内存泄露如何检测?

349 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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)
  1. 如果执行完毕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中的垃圾回收算法

  • 引用计数算法
  • 标记清除算法
    • 标记清除算法是一种直接的全面停顿算法。简单的说,它们找出所有不可达的对象,并将它们放入空闲列表Free。
    • JS性能优化之标记清除算法

曾经非常经典的内存泄露

在 IE6-IE7中

var div1 = document.getElementById('div1')
div.a = div1
div1.someBigData = { 
    //内存占用很大的数据
}

这样就会导致内存泄露,内存泄露是一些非预期的垃圾回收不了。预期的,比如闭包等就不算是内存泄露了。