面试高频题:JS的内存泄露与垃圾回收机制

202 阅读2分钟

一、内存泄漏

1. 什么是内存泄漏?

内存泄漏是指内存被分配但无法被回收的情况。程序中不再使用的变量或对象依然被引用,导致内存占用不断增加,最终可能导致性能下降甚至程序崩溃。

2. 常见内存泄漏场景

  • 未清理的全局变量:如果变量未用 var/let/const 声明,会成为全局变量,导致内存泄漏。

  • 闭包导致的多余引用:闭包引用了外部变量,但这些变量不再需要时,仍无法被回收。

  • DOM 元素未正确释放:删除 DOM 元素后,仍有引用保留,无法释放内存。

  • 定时器或回调未清理:setInterval 或异步回调未清理,引用持续存在。

  • 事件监听未移除:添加的事件监听器未正确移除,导致内存泄漏。

二、垃圾回收机制

JavaScript 使用自动垃圾回收(GC, Garbage Collection)来释放内存。它会自动查找和清理无用的内存块。

1. 垃圾回收的核心思想

(1) 可达性(Reachability)

一个对象被称为“可达”,如果程序可以通过某些方式访问它:

  • 从全局变量访问。
  • 被某个闭包或对象引用。

任何无法访问的对象会被标记为“不可达”,随后被清理。

2. 垃圾回收算法

(1) 标记清除(Mark-and-Sweep)

  • 是最常用的垃圾回收算法。
  • 垃圾回收器会遍历所有对象,标记可达的对象为“活跃”。
  • 没有被标记的对象会被释放。

(2) 引用计数(Reference Counting)

  • 每个对象维护一个引用计数,当计数为 0 时释放对象。
  • 循环引用问题:如果两个对象互相引用,引用计数永远不会为 0。

3. 垃圾回收的触发时机

  • 内存占用达到一定阈值。
  • 空闲时(浏览器空闲时间会触发 GC)。

三、内存泄漏检测方法

1 使用 Chrome DevTools

步骤:

  1. 打开 Chrome 开发者工具(F12)。
  2. 进入 Memory 面板。
  3. 使用以下三种选项检测:
    • Heap Snapshot:生成当前内存快照,分析对象占用内存。
    • Allocation instrumentation on timeline:监控内存分配随时间变化的情况。
    • Allocation sampling:采样记录内存分配的热点。

操作步骤:

  1. Heap Snapshot 分析:

    • 点击 Take Snapshot,生成快照。
    • 多次操作后生成快照,对比对象数量和大小是否有异常增长。
    • 搜索 Detached DOM,检查是否存在未释放的 DOM 元素。
  2. 观察内存曲线:

    • 进入 Performance 面板。
    • 点击 Start profiling and reload page
    • 模拟用户操作,观察内存曲线是否持续增长不下降。

2 使用 Lighthouse

  1. 打开 Chrome 开发者工具。
  2. 进入 Lighthouse 面板,生成性能报告。
  3. 检查内存相关的性能优化建议。