垃圾回收与内存泄漏

126 阅读2分钟

垃圾回收

  • JavaScript根据“可达性”判断是否应该进行垃圾回收,
  • 全局变量,当前执行的函数,它的局部变量和参数,嵌套调用链上的变量和参数,这些值被称为,从根出发,能通过引用或者引用链进行访问的值,就被称为可达值。不属于可达值的,就应该被垃圾回收。

整个标记清除算法大致过程就像下面这样

  • 垃圾收集器在运行时会给内存中的所有变量都加上一个标记,假设内存中所有对象都是垃圾,全标记为0
  • 然后从各个根对象开始遍历,把不是垃圾的节点改成1
  • 清理所有标记为0的垃圾,销毁并回收它们所占用的内存空间
  • 最后,把所有内存中对象标记修改为0,等待下一轮垃圾回收

内存泄漏

没有用的内存没有被回收,就可能会造成内存泄漏。

刻意制造的内存泄漏,不断新增全局属性和监听器

import { useEffect } from "react";

function Home() {
  useEffect(() => {
    setInterval(() => {
      const num = Math.random() * 10;
      const property = `a${num}`;
      // 不断增加的全局属性
      (window as Record<string, any>)[property] = { obj: 1 };
      console.log({ window });
      // 不断增加的监听器
      window.addEventListener("click", function () {
        console.log("----------");
      });
    }, 100);
  });
  return <div>Home</div>;
}

export default Home;

使用performance面板记录一段时间

内存和监听器数量飙升

memory面板,记录快照

两次快照对比,可以知道新增了哪些东西,根据这些信息去代码里排查

常见的内存泄漏场景

  • 过多的全局变量
  • 闭包,变量也不会被回收
  • 没有取消事件监听器

参考

如何排查网页在哪里发生了内存泄漏?

垃圾回收

「硬核JS」你真的了解垃圾回收机制吗