一文详解JavaScript中的常见内存泄漏和解决方法

 更新时间:2026年02月27日 09:11:20   作者:小黑的铁粉  
在 JavaScript 中,内存泄漏指的是应用程序不再需要某块内存,但由于某种原因,垃圾回收机制无法将其回收,导致内存占用持续升高,最终可能引发性能下降或崩溃,下面我们就来看看有哪些常见的内存泄漏情况吧

在 JavaScript 中,内存泄漏指的是应用程序不再需要某块内存,但由于某种原因,垃圾回收机制(GC, Garbage Collection)无法将其回收,导致内存占用持续升高,最终可能引发性能下降或崩溃。

以下是 JavaScript 中导致内存泄漏的最常见情况及示例:

1. 意外的全局变量

在 JavaScript 中,如果未声明的变量被赋值,它会自动成为全局对象的属性(浏览器中是 window,Node.js 中是 global)。全局变量在页面关闭前永远不会被垃圾回收。

function leak() {
  // 忘记了使用 let/const/var
  secretData = "这是一段敏感数据"; // 变成了 window.secretData
}
leak();

解决方案:

  • 使用严格模式 ('use strict') 来避免意外的全局变量。
  • 使用完后手动设置为 null

2. 被遗忘的定时器或回调函数

如果代码中设置了 setIntervalsetTimeout,但忘记清除(clear),且定时器内部引用了外部变量,那么这些变量无法被释放。

const someResource = hugeData(); // 很大的数据

setInterval(function() {
  // 这个回调引用了 someResource
  console.log(someResource);
}, 1000);

// 如果没有调用 clearInterval,someResource 会一直留在内存中

解决方案:

在组件卸载或页面关闭时,清除定时器:clearInterval(id)

3. 闭包(Closures)的不当使用

闭包是 JavaScript 的强大特性,但如果闭包长期持有父函数的变量,而这些变量又很大,就会造成泄漏。

function outer() {
  const largeArray = new Array(1000000).fill('data');

  return function inner() {
    // inner 函数引用了 outer 作用域的 largeArray
    // 只要 inner 函数还存在,largeArray 就无法被回收
    console.log(largeArray.length);
  };
}

const innerFunc = outer(); // largeArray 被保留
// 如果后续没有释放 innerFunc,内存就会泄漏

解决方案:

  • 确保不再需要的函数被释放(innerFunc = null)。
  • 在闭包外尽量避免引用大对象。

4. DOM 引用未被清理

当把 DOM 元素存储为 JavaScript 对象或数据结构时,即使该元素已从 DOM 树中移除,只要 JS 中还有引用,该 DOM 元素连同其事件监听器就不会被释放。

const elements = {
  button: document.getElementById('button')
};

function removeButton() {
  document.body.removeChild(document.getElementById('button'));
  // 注意:elements.button 仍然指向那个 DOM 对象,所以它无法被回收
}

解决方案:

移除 DOM 节点后,同时将变量设置为 null

5. 事件监听器未移除

向 DOM 元素添加了事件监听器,但在移除该元素前没有移除监听器。现代浏览器(尤其是针对原生 DOM 的监听器)处理得比以前好,但在单页应用(SPA, Single Page Application)中,如果频繁添加和移除元素,累积的监听器仍会导致泄漏。

const element = document.getElementById('button');
element.addEventListener('click', onClick);

// 如果后来 element 被移除了,但没有 removeEventListener
// 并且 onClick 函数引用了外部变量,就会造成泄漏

解决方案:

  • 在移除元素前调用 removeEventListener
  • 使用框架(如 React、Vue)时,框架的生命周期通常会自动处理,但要注意在 useEffect 的清理函数中移除原生监听器。

6. 脱离 DOM 树的引用(DOM 树内部引用)

这通常发生在给 DOM 元素添加自定义属性时。如果两个 DOM 元素相互引用,即使从文档流中移除,也可能因为循环引用导致泄漏(在老版本 IE 中常见,现代浏览器有所改进,但仍需注意)。

7. Map 或 Set 的不当使用

使用对象作为 MapSet 的 key,如果只把 key 置为 null,而没有从 Map 中删除它,key 依然被 Map 引用着,无法被回收。

let obj = {};
const map = new Map();
map.set(obj, 'some value');

obj = null; // 这里 obj 被置为 null
// 但 map 里仍然有对原对象的引用,所以原对象无法被回收

解决方案:

使用 WeakMapWeakSet。它们的 key 是弱引用,不会阻止垃圾回收。

8. console.log 的影响

在开发环境调试时打印对象,如果线上环境忘记删除 console.log,控制台会一直持有对象的引用(特别是打印复杂对象时),导致对象无法被回收。现代浏览器在处理 console.log 时有所优化,但仍需注意。

建议:

生产环境打包时移除所有 console.log

总结:如何避免内存泄漏

1.使用 WeakMapWeakSet 存储对象引用。

2.及时清理:清除定时器、取消订阅、解绑事件。

3.避免全局变量,使用 let/const 和严格模式。

4.合理使用闭包,避免在闭包中持有大量数据的引用。

5.善用工具

  • 使用 Chrome DevTools 的 Memory 面板拍摄堆快照(Heap Snapshot),分析内存占用。
  • 使用 Performance 面板监控内存变化。

到此这篇关于一文详解JavaScript中的常见内存泄漏和解决方法的文章就介绍到这了,更多相关JavaScript常见内存泄漏内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • webpack中如何使用雪碧图的示例代码

    webpack中如何使用雪碧图的示例代码

    这篇文章主要介绍了webpack中如何使用雪碧图的示例代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-11-11
  • Bootstrap编写一个在当前网页弹出可关闭的对话框 非弹窗

    Bootstrap编写一个在当前网页弹出可关闭的对话框 非弹窗

    这篇文章主要介绍了Bootstrap编写一个在当前网页弹出可关闭的对话框,不用跳转,非弹窗,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • js微信支付实现代码

    js微信支付实现代码

    这篇文章主要为大家详细介绍了javascript微信支付的相关代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-12-12
  • JavaScript弹出框与事件绑定的超详细解析

    JavaScript弹出框与事件绑定的超详细解析

    这篇文章主要介绍了JavaScript弹出框与事件绑定的相关资料,通过示例讲解了实现方式、综合应用及最佳实践,如避免内存泄漏、优化性能、提升用户体验与可访问性,需要的朋友可以参考下
    2025-05-05
  • 一些javascript一些题目的解析

    一些javascript一些题目的解析

    今天做了群友发的一个链接, 关于js 的一些题目的. 这样的题目常常有很多陷阱在里面,等着别人去踩. 很不幸,洒家踩了, 还蛮悲剧.
    2010-12-12
  • 重新理解JavaScript的六种继承方式

    重新理解JavaScript的六种继承方式

    通过本文带领大家一起重新理解JavaScript的六种继承方式,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-03-03
  • Bootstrap每天必学之导航条(二)

    Bootstrap每天必学之导航条(二)

    Bootstrap每天必学之导航条,进一步向大家讲解了导航条养殖,以及导航条中元素的使用方法,感兴趣的小伙伴们可以参考一下
    2016-03-03
  • v3-admin-vite 整合pont的详细过程

    v3-admin-vite 整合pont的详细过程

    这篇文章主要介绍了v3-admin-vite 整合pont的详细过程,目前后端的Admin模板使用的是v3-admin-vite,需要整合pont接口,方便前后端统一一体化开发,本文给大家介绍的非常详细,需要的朋友可以参考下
    2024-03-03
  • 利用JS判断鼠标移入元素的方向

    利用JS判断鼠标移入元素的方向

    本文对JS判断鼠标移入元素的方向的实现方法进行介绍,并分享了完整的示例代码,有需要的朋友可以看下
    2016-12-12
  • js实现音乐播放器

    js实现音乐播放器

    这篇文章主要为大家详细介绍了js实现音乐播放器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-07-07

最新评论