JavaScript 闭包 内存泄漏与解决办法

闭包的优缺点:

优点:①封装功能 ②防止全局变量污染 ③ 延长变量的生命周期,缓存上一次执行的结果 ④实现局部变量/函数私有化

缺点:①浪费内存(尤其是引用了较大的对象)

注意事项:①因为调用函数会创建闭包,所以要避免嵌套调用/递归调用闭包函数


闭包垃圾回收:

由于闭包的应用场景很多,以及本人水平有限,所以以下内容可能不是很适合您所需要的场景,请您见谅~

回归正题:如下代码,返回的函数中包含了对内部数组的引用

注:引用arr是存放在栈中的,new Array(10000)创建的数组存放在堆中的

function fn1() {
    let arr = new Array(10000000)
    arr[0] = 1
    return function () { 
        return arr[0]  //此时,由于引用一直保存着,所以不会回收这个数组空间
    }
}

let getArr0 = fn1()
let arr0 = getArr0()
console.log(arr0)

运行时堆内存图:
闭包内存泄漏与解决办法
可以看到,在很长时间内,该数组仍然被存放在堆内存中无法释放

修改办法:加了一句代码

function fn1() {
    let arr = new Array(10000000)
    arr[0] = 1
    return function () { 
        return arr[0] 
    }
}

let getArr0 = fn1()
let arr0 = getArr0()
getArr0 = null // + 将调用fn1()生成的函数对象(在JavaScript中,函数也是对象)置为null
console.log(arr0) 

运行时堆内存图:
闭包内存泄漏与解决办法
这回可以看到,堆内存很快就被释放了


原理:

闭包内存泄漏与解决办法
如图,返回的函数中包含了数组的引用(即arr),即我们在调用fn1()时生成的getArr0对象(函数)中包含了arr变量,即数组的引用。

再次说明:new Array()用于创建数组,存放在堆中,变量arr是对这个数组的引用,指向数组,放在栈中

因为getArr0对象是定义在全局作用域上的,只能随着程序的销毁而销毁,所以getArr0对象与数组之间的引用在程序销毁前也会一直保留

如果此时手动将getArr0对象置为null,那么此时getArr0对象就立刻失去了对堆中数组的引用,此时堆中的这个数组,已经没有引用指向它了,所以会在垃圾收集器在下次垃圾清理的时候,会将这块内存回收。


总结

①解除返回的函数对象内部局部对象之间的引用是关键
②对于dom操作,如果在内部函数中添加了事件监听,那么在将内部函数调用完毕后置为null之前,先将该事件解绑

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值