闭包、内存泄漏、垃圾回收详解

首先要说清楚这个话题,必须要先清楚什么是垃圾回收,要清楚什么是垃圾回收呢,必须要知道什么是垃圾,所谓的垃圾就是不再需要的内存,需要或者不需要是由人为来决定的

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <button>点击</button>
  </body>
  <script>
    const createIncrease = () => {
      const doms = new Array(10000).fill(0).map((_, i) => {
        const dom = document.createElement("div");
        dom.innerHTML = 1;
        return dom;
      });
      const increase = () => {
        doms.forEach((e) => {
          e.innerHTML = Number(e.innerHTML) + 1;
        });
      };
      return increase;
    };
    const increase = createIncrease();
    const btn = document.querySelector("button");
    btn.addEventListener("click",increase);
  </script>
</html>

就比如上面的代码,这个doms很明显是需要的内存,因为每次点击按钮都会执行increase这个函数,这个函数里面用到了doms,所以doms不是垃圾

 const nums = [1,2,3,4,5];
 const sum = nums.reduce((pre,next) =>{
     return pre + next
 },0);
console.log(sum);

上面的nums是不是垃圾呢,不是垃圾,虽然看起来这三行代码运行结束后,没有再需要nums的地方了,按道理是不再需要的东西了,但是可以在浏览器的控制台打印这个nums,所以它不是垃圾
在这里插入图片描述
所以需不需要得问自己,毕竟是我们在写代码,只有我们清楚后续代码还需不需要,所以垃圾就是我们能清楚知道后续不再使用的内存
现在搞清楚了垃圾,那么再来搞清楚垃圾回收,js里面是有一个垃圾回收器来帮助我们回收不再需要的内存,但是这个玩意儿它根本不知道这个内存需不需要,就比如上面的nums不也没有回收嘛,但是它知道有一些东西一定是我们不需要的,那就是连我们自己都访问不到的内存,举个例子

  let nums = [1,2,3];
  nums = [4,5];
  const sum = nums.reduce((pre,next) =>{
      return pre + next
  },0);
  console.log(sum);

nums被重新赋值后,很明显,数组[1,2,3]的内存我们已经没有任何机会再访问到了,被称为无法触达的内存空间,这一类内存就会被垃圾回收器定义为垃圾,这就是垃圾回收
那什么是内存泄漏呢,就是我们不再需要使用的内存空间依旧能够触达,导致垃圾回收器并不能将其回收,也就是上面例子中的nums,当内存泄漏过多的时候,就会影响代码的运行,因此需要手动将其变成无法触达的内存空间,操作很简单,在代码最后将nums赋值为null,那么数组[1,2,3]的内存空间将变成无法触达,也就会被垃圾回收器回收了

 let nums = [1,2,3];
 const sum = nums.reduce((pre,next) =>{
    return pre + next
 },0);
 nums = null;
 console.log(sum);

所以不仅仅是闭包才会造成内存泄漏,正常定义了变量最后没有设置为null也会导致内存泄漏
闭包内存泄漏的原因主要有两点:

  • 持有了不再需要的函数引用,会导致函数关联的词法环境无法销毁,从而导致内存泄漏
  • 当多个函数共享词法环境时,会导致词法环境膨胀,从而导致出现无法触达但也无法回收的内存空间,从而导致内存泄漏
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <button>点击</button>
  </body>
  <script>
    const createIncrease = () => {
      const doms = new Array(10000).fill(0).map((_, i) => {
        const dom = document.createElement("div");
        dom.innerHTML = 1;
        return dom;
      });
      const increase = () => {
      };
      const test = () =>{
        doms
      }
      return increase;
    };
    const increase = createIncrease();
    const btn = document.querySelector("button");
    btn.addEventListener("click",() =>{
        increase()
    });
  </script>
</html>

上面的例子中,increase函数并没有使用doms,test函数中使用了,但是test函数根本访问不到,但是因为它和increase函数共享词法环境,导致doms即使是无法触达的内存空间依旧无法被回收

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值