垃圾回收
- 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面板,记录快照
两次快照对比,可以知道新增了哪些东西,根据这些信息去代码里排查
常见的内存泄漏场景
- 过多的全局变量
- 闭包,变量也不会被回收
- 没有取消事件监听器