js---js使用闭包是否会产生内存泄露及解决方案

一、前置知识

闭包的产生

js垃圾回收机制

不懂的可以先移步到下方的博客再回来

「前端进阶」JS中的内存管理 - 知乎

二、闭包是否会产生内存泄露

在此强调变量arr保存的是对引用数据类型数组的引用(地址),保存在中;数组的每一项值保存在中,new Array(10000000)大约占据40mb内存

案例1:

    function fn() {
      //fn函数作用域的局部变量arr
      const arr = new Array(10000000)
      function fn1() {
        // 在fn1函数作用域下访问(依赖)外层fn函数作用域的局部变量arr,此时会产生闭包
        console.log(arr[0]);
      }
      fn1()
    }
    fn()

打开控制台进行断点查看:

打开控制台进行性能分析: 

 ps:函数在执行时一开始由于创建了new Array(10000000),所以占据了堆中大概40mb内存,也就是一个Array(10000000)的大小,不过在很快的一段时间内变为了1.3mb,也就是js的垃圾回收机制在闭包函数运行后成功后在一段时间后把闭包产生的内存垃圾(new Array(10000000))给清理掉了

案例二:

    function fn() {
      const arr = new Array(10000000)
      function fn1() {
        console.log(arr[0]);
      }
      return fn1
    }
    fn()()

打开控制台进行断点查看:

打开控制台进行性能分析: 

 ps:跟案例1一样,不会造成内存浪费,不多加解释

案例3:


    function fn() {
      const arr = new Array(10000000)
      function fn1() {
        console.log(arr[0]);
      }
      return fn1
    }
    //变量test由于保存了fn1函数的引用,而fn1函数作用域内又依赖于fn作用域的Array(10000000),
    // 所以导致Array(10000000)在堆内存中无法被释放
    let test = fn()
    test()

打开控制台进行断点查看: 

 打开控制台进行性能分析: 

ps:

js垃圾回收机制的一个算法是标记清除法:

  一、即能被标记的到的变量,说明变量可能会在某一个时间点需要用到,所以垃圾回收机制不会将该变量进行回收,一直存放在内存中,直到页面浏览器的关闭,变量才会被释放

二、就比如像全局作用域下的变量,整个代码线程运行过程中,全局变量都存在于内存中,因为全局变量不知道在什么时候会再次使用,所以js会使用(window.全局变量)对全局变量进行标记,所以对标记到的全局变量不会进行回收

①在本案例中闭包函数运行时由于创建了 new Array(10000000),所以占据了堆中大概40mb内存,再有全局变量test由于保存了fn1函数的引用,而fn1函数作用域内又依赖于fn作用域的Array(10000000),导致js垃圾回收机制通过全局变量test---》fn1函数---》Array(10000000),从而找到Array(10000000)进行标记,所以js不会对存在堆内存的中Array(10000000)进行回收,导致堆内存中的Array(10000000)(40mb)一直无法释放。从而造成内存浪费。

解决方案:

通过设置变量为null将标记链断开,修改本案例如下:


    function fn() {
      const arr = new Array(10000000)
      function fn1() {
        console.log(arr[0]);
      }
      return fn1
    }
    //变量test由于保存了fn1函数的引用,而fn1函数作用域内又依赖于fn作用域的Array(10000000),
    // 所以导致Array(10000000)在堆内存中无法被释放
    let test = fn()
    test()
    test = null

 ps:通过将全局变量test的值设为null,全局变量test无法再依赖fn1函数---》Array(10000000),从而无法对Array(10000000)进行标记,所以js会对存在堆内存的中Array(10000000)进行回收,导致堆内存中的Array(10000000)(40mb)释放。不会造成内存浪费。

案例4:

    function fn() {
      const arr = new Array(10000000)
      function fn1() {
        console.log(arr[0]);
        return new Array(10000000)
      }
      return fn1
    }
    let test = fn()
    let arr = test()

  打开控制台进行性能分析:

ps:80mb大概就是两个 Array(10000000)的内存大小,因为全局变量test,arr一直保持对Array(10000000)的引用,所以导致js垃圾回收机制无法回收,

解决方案:

设置变量设置为null

    function fn() {
      const arr = new Array(10000000)
      function fn1() {
        console.log(arr[0]);
        return new Array(10000000)
      }
      return fn1
    }
    let test = fn()
    let arr = test()
    test = null
    arr = null

   打开控制台进行性能分析:

ps:经过设置变量为null,从而将内存浪费进行释放 

三、总结

1.使用闭包是否一定会产生内存浪费吗?

答:不一定,闭包是否产生内存浪费取决于js的垃圾回收机制是否将变量占用的内存给及时清除掉,常见的垃圾回收算法有标记清除法,能标记到就不回收,反之则回收。一般如果闭包函数没有返回值或者没有使用全局变量对闭包函数的返回值进行存储,那么是不会造成内存浪费的,详见文章的案例1和案例2;而如果闭包函数存在返回值并且使用全局变量对闭包函数的返回值进行存储,那么可能会造成内存浪费的,详见案例3和案例4

2.如何解决闭包产生的内存浪费

通过设置变量为null即可间接或直接释放内存浪费,变量使用完毕后及时设置为null即可

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
闭包内存泄漏的解决方法有以下几种: 1. 及时释放引用:在不再需要使用闭包时,手动将闭包中的变量设置为null,以便让垃圾回收机制回收内存。 2. 减少闭包使用:尽量避免过度使用闭包,因为闭包占用更多的内存。可以考虑使用其他方式来实现相同的功能,如使用模块化的设计模式。 3. 使用事件委托:当使用闭包来处理事件时,可以考虑使用事件委托的方式,将事件处理函数绑定在父元素上,避免在每个子元素上都创建一个闭包。 4. 避免循环引用:闭包中的变量引用了外部函数的作用域,而外部函数的作用域又引用了闭包中的变量,这种情况下就出现循环引用。为了避免循环引用导致内存泄漏,可以在不需要使用闭包时,手动解除对外部函数作用域的引用。 总之,解决闭包内存泄漏的关键是及时释放引用、减少闭包使用使用事件委托和避免循环引用。通过合理的代码设计和内存管理,可以有效地避免闭包内存泄漏的问题。\[1\]\[2\]\[3\] #### 引用[.reference_title] - *1* [什么是闭包,如何解决闭包的内存泄漏](https://blog.csdn.net/Kiruthika/article/details/106930874)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [什么是闭包闭包造成的内存泄露如何解决](https://blog.csdn.net/yiyueqinghui/article/details/96453390)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cirrod

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值