You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

原生JavaScript内存泄漏成因、代码示例及正确清理方法咨询

原生JavaScript内存泄漏:成因、示例与修复方法

一、内存泄漏的具体成因

  • 意外全局变量:未声明的变量会自动挂载到window对象,长期占用内存无法被回收
  • 闭包滥用:闭包会保留对外部作用域变量的引用,导致这些变量无法被垃圾回收器(GC)清理
  • 未清理的DOM引用:移除DOM元素后,JS代码中仍保留对该元素的引用,导致DOM节点无法被回收
  • 遗忘的定时器/间隔器:定时器回调函数引用外部变量,只要定时器不停止,关联变量就会一直被占用
  • 未移除的事件监听器:DOM元素被移除后,对应的事件监听器未解绑,监听器和关联变量无法被GC回收
  • 无限增长的缓存:用对象或Map做缓存时,未设置过期或清理机制,缓存体积持续膨胀

二、引发内存泄漏的代码示例

1. 意外全局变量

function doSomething() {
  // 未用let/const声明,自动成为window的属性
  leakVar = "我是意外泄漏的全局变量";
}
doSomething();

2. 闭包滥用

function createClosure() {
  // 占用大量内存的对象
  const bigData = new Array(1000000).fill('海量数据');
  return function() {
    // 闭包保留了对bigData的引用,即使createClosure执行完毕,bigData也不会被回收
    console.log(bigData.length);
  }
}
// 持有闭包函数的引用,导致bigData一直存在
const keepAlive = createClosure();

3. DOM引用未清理

const button = document.getElementById('myButton');
// JS对象保留对DOM元素的引用
const buttonRef = { element: button };

// 移除DOM元素,但buttonRef仍持有引用
document.body.removeChild(button);

4. 遗忘的定时器

const largeObject = { data: new Array(1000000).fill('测试数据') };

// 定时器回调引用largeObject,只要定时器运行,该对象就无法被回收
setInterval(() => {
  console.log(largeObject.data.length);
}, 1000);

5. 未移除的事件监听器

const container = document.getElementById('container');
const handleClick = () => {
  console.log('容器被点击');
};

container.addEventListener('click', handleClick);

// 移除容器,但事件监听器未解绑
document.body.removeChild(container);

三、内存释放与修复方法

1. 修复意外全局变量

  • 开启严格模式避免未声明变量,或手动清理不再需要的变量:
'use strict'; // 严格模式下未声明变量会直接报错
function doSomething() {
  let leakVar = "局部变量";
  // 不需要时手动释放引用
  leakVar = null;
}
doSomething();

2. 修复闭包滥用

  • 当闭包不再需要时,解除对闭包函数的引用:
function createClosure() {
  const bigData = new Array(1000000).fill('海量数据');
  return function() {
    console.log(bigData.length);
  }
}
let keepAlive = createClosure();
// 不再使用闭包时,解除引用让GC回收关联变量
keepAlive = null;

3. 修复DOM引用未清理

  • 移除DOM元素后,手动清除JS中对应的引用:
const button = document.getElementById('myButton');
const buttonRef = { element: button };

document.body.removeChild(button);
// 清除对DOM元素的引用
buttonRef.element = null;

4. 修复遗忘的定时器

  • 使用clearInterval/clearTimeout清除不再需要的定时器,同时释放关联变量:
const largeObject = { data: new Array(1000000).fill('测试数据') };
const timer = setInterval(() => {
  console.log(largeObject.data.length);
}, 1000);

// 停止定时器
clearInterval(timer);
// 释放大对象的引用
largeObject.data = null;

5. 修复未移除的事件监听器

  • 移除DOM元素前,先解绑对应的事件监听器:
const container = document.getElementById('container');
const handleClick = () => {
  console.log('容器被点击');
};

container.addEventListener('click', handleClick);

// 移除前先解绑监听器
container.removeEventListener('click', handleClick);
document.body.removeChild(container);

6. 缓存的合理管理

  • 给缓存设置过期时间,或限制缓存大小,定期清理无用数据:
const cache = new Map();

// 添加缓存时记录时间戳
function addToCache(key, value) {
  cache.set(key, { value, timestamp: Date.now() });
}

// 清理1小时前的过期缓存
function cleanCache() {
  const now = Date.now();
  for (const [key, item] of cache.entries()) {
    if (now - item.timestamp > 3600000) {
      cache.delete(key);
    }
  }
}

// 每小时执行一次缓存清理
setInterval(cleanCache, 3600000);

内容的提问来源于stack exchange,提问作者King是太阳

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.01 17:17:26