闭包与内存泄漏问题

面试过程中经常会有面试官考到这么一题,问你闭包会不会导致内存泄露。接下来就对于这个问题讨论出一个完美的答案。

首先什么是内存泄露?那就是有垃圾没有被回收,这里的垃圾指的是我们不再需要的内存空间。那么我们指的是谁?那就是开发者也就是程序员。

接下来看这个例子:

    let nums = [1, 2, 3, 4, 5];
    const sum = nums.reduce((total, num) => total + num, 0)
    console.log(sum);

在上述例子中我们定义了数组nums,目的是为了求和然后打印出结果,那么结果打印了之后这个数组nums还是否需要呢?如果不需要那么数组nums就是垃圾,如果后续还需要这个nums数组那么就不是垃圾。所以说需不需要,一定是由程序员来决定的。那么程序是如何知道哪些是你不用,那么就是你根本访问不了的东西,只要这个数据永远不可能访问到,那么就会被垃圾回收器发现。其中方法有引用计数法、标记清除法。

闭包是会增加内存泄漏的风险,注意不是闭包一定会导致内存泄漏!

闭包会在两种情况下造成内存泄漏

第一种情况:

    function createIncrease() {
      const doms = new Array(100000).fill(0).map((_, i) => {
        const dom = document.createElement('div');
        dom.innerHTML = i;
        return dom;
      })
      function increase() {
        doms.forEach((dom) => {
          dom.innerHTML = Number(dom.innerHTML) + 1;
        })
      }
      return increase;
    }
    const increase = createIncrease()
    const btn = document.querySelector('button');
    btn.addEventListener('click', increase)

上述代码中,假设button这个点击事件只需要触发一次,那么就存在内存泄露,因为垃圾回收器不敢回收increase,因为你点击button的时候是需要执行increase这个函数的。而这个increase函数内部是有个闭包,最终导致了内存泄露。

总结:当本应该被销毁的函数未被销毁,导致其关联的此法环境无法销毁,造成内存泄漏。

那么怎么解决呢?,其实根源就在这个本应该被销毁的函数没有被销毁,那么把他销毁就好了。

    function createIncrease() {
      const doms = new Array(100000).fill(0).map((_, i) => {
        const dom = document.createElement('div');
        dom.innerHTML = i;
        return dom;
      })
      function increase() {
        doms.forEach((dom) => {
          dom.innerHTML = Number(dom.innerHTML) + 1;
        })
      }
      return increase;
    }
    // const increase = createIncrease()
    const btn = document.querySelector('button');
    btn.addEventListener('click', createIncrease(),{
      once:true,
    })

第二种情况:

    function createIncrease() {
      const doms = new Array(100000).fill(0).map((_, i) => {
        const dom = document.createElement('div');
        dom.innerHTML = i;
        return dom;
      })
      function increase() {//temp函数和increase函数是共享同一个词法环境

      }
      function temp() {
        doms;
      }
      return increase;
    }
    let increase;
    const btn = document.querySelector('button');
    btn.addEventListener('click', () => {
      increase = createIncrease();
      increase();
    })

temp函数和increase函数是共享同一个词法环境,increase函数中并没有使用dom,但是temp函数中使用了doms。因为increase和temp书亦同一个词法环境,那么词法环境会保留住这个doms,因为如果不保留temp函数以后用啥呀。那么当整个createIncrease函数执行完毕,temp函数会被销毁,但是词法环境中的doms并未被销毁。这个牵扯复杂原理,总之浏览器并没销毁词法环境中的doms。最终导致内存泄漏。

此时再看上述代码,点击按钮触发的函数其实就只有createIncrease函数中的increase函数,但是如果打开f12的memory一进去打个快照,然后多次点击按钮,然后点击垃圾回收,然后再打个快照,发现内存变大,并未回收掉。

总结:当多个函数共享词法环境时,可能导致词法环境膨胀,从而可能导致出现无法触达但也无法回收的内存空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

柑橘乌云_

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

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

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

打赏作者

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

抵扣说明:

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

余额充值