当前位置: 首页 > news >正文

Js 垃圾回收 与 内存泄漏

首先需要了解 内存生命周期 基础概念:

1.分配所需内存

2.在内存中进行逻辑读/写

3.垃圾清除,释放/回收内存

        即 分配内存 → 使用内存 → 释放内存

        其中 使用内存 在所有语言中都一样。

        但 分配内存 和 释放内存 的逻辑在如 C++ 中的底层语言中是明确的,但在JS这种高级语言中,大部分是隐藏的,JS在定义一个变量时,就已经定义好了内存,同时也提供了垃圾回收的机制,自动回收不再使用的内存。

垃圾回收:

        本质是找到内存中可以释放的变量,进行释放 回收内存。

内存泄漏:

        本质是程序对一段内存失去了控制权:程序认为一个变量已经没用了,但垃圾回收引擎认为这个变量还在使用 不能释放,从而导致这段内存不能释放。

        注意内存突然暴增不等于内存泄漏,只能说代码性能没有做好,需要优化。

        泄漏的本质在于能否控制,而不是突然的增量有多少。

常见的JS内存泄漏情况:

1.意外的全局变量

原因:未声明的变量会被隐式创建为全局变量(window 对象的属性),除非手动释放,否则会一直存在。

function leak() {
  // 未使用 var/let/const,变量变为全局
  globalVar = 'This is a global variable'; 
  this.anotherGlobal = 'Another global via this';
}
leak(); // 执行后,globalVar 和 anotherGlobal 成为全局变量

解决:使用严格模式("use strict"),或始终用 let/const 声明变量。

2.未清除的定时器或回调

原因setInterval 或 setTimeout 的回调中引用了外部变量,定时器未清除时,变量无法释放。 

let bigData = new Array(1000000).fill('data');

const timer = setInterval(() => {
  console.log(bigData.length); // 定时器持有 bigData 的引用
}, 1000);

// 即使不再需要 bigData,若不调用 clearInterval(timer),内存无法释放

解决:及时用 clearInterval/clearTimeout 清除定时器。

3. ​闭包长期持有外部变量

function createClosure() {
  const hugeData = new Array(1000000).fill('data');
  return () => console.log(hugeData[0]); // 闭包引用了 hugeData
}

const closure = createClosure(); 
// closure 长期存在时,hugeData 无法被回收

解决:在不需要时解除对闭包的引用(如 closure = null)。

4. ​未移除的 DOM 事件监听

原因:DOM 元素被移除后,若事件监听器未移除且回调中引用了该元素,元素无法被回收。

function addListener() {
  const button = document.getElementById('button');
  button.addEventListener('click', () => {
    console.log('Button clicked'); // 闭包引用了 button
  });
}
addListener();

// 即使从 DOM 中移除 button,事件监听器仍持有其引用

解决:使用 removeEventListener 或在元素移除前解绑事件。

5. ​残留的 DOM 引用

原因:JS 中保留了对已移除 DOM 元素的引用,导致元素无法被 GC 回收。

const elements = [];
function addElement() {
  const div = document.createElement('div');
  elements.push(div); // 将 DOM 元素存入数组
  document.body.appendChild(div);
}

// 即使调用 document.body.removeChild(div),elements 数组仍保留引用

解决:手动清理数组(如 elements.length = 0)。

6. ​脱离的 DOM 树引用

原因:父节点从 DOM 移除,但子节点仍被 JS 引用,导致整个子树无法回收。

let parent = document.createElement('div');
let child = document.createElement('p');
parent.appendChild(child);
document.body.appendChild(parent);

// 从 DOM 移除 parent
document.body.removeChild(parent);

// 若其他地方仍引用 child,parent 和 child 均无法释放

解决:解除对子节点的引用(如 child = null)。

7. ​无限增长的缓存

原因:缓存对象未设置清理策略,导致数据持续占用内存。

const cache = {};
function setCache(key, value) {
  cache[key] = value; // 不断添加新键值对,无清理机制
}

// 长期运行后,cache 占用内存无限增长

解决:使用 LRU(最近最少使用)算法或设置过期时间清理缓存。

相关文章:

  • java当中的list集合
  • 第十四天- 排序
  • 轻量级TLS反向代理工具TLS-reverse-proxy:打造安全通信桥梁
  • 基于springboot的校园资料分享平台(048)
  • 307 Temporary Redirect 解决办法 httpx
  • 如何安全解除PDF文件密码?实测免费工具操作指南
  • Live555+Windows+MSys2 编译Androidso库和运行使用
  • scrapy_yield详解
  • JSON 简介
  • COBOL语言的安全开发
  • Spring Boot(十六):拦截器Interceptor
  • Android7 Input(一)Android Input服务初始化
  • anythingLLM结合searXNG实现联网搜索
  • LeetCode Hot 100 - 子串 | 560.和为K的子数组、239.滑动窗口最大值、76.最小覆盖子串
  • 【Vue3入门1】03-Vue3的基本操作(下)
  • Cocos Creator Shader入门实战(五):材质的了解、使用和动态构建
  • 推荐一个智能抠图与背景替换工具,支持docker部署、API调用
  • go复习目录
  • 基于Sentinel-1A GRD洪涝淹没范围提取(SDWI阈值法和OSTU自动阈值法)
  • .NET 10 新的 JsonIgnoreCondition
  • 上海团队在医学顶刊连发两文,率先提出“证据污染”循证概念
  • 地下5300米开辟“人造气路”,我国页岩气井垂深纪录再刷新
  • 专访|导演刘江:给谍战题材注入现实主义的魂
  • 水豚“豆包”出逃已40天,扬州茱萸湾景区追加悬赏
  • 十大券商看后市|A股中枢有望逐步震荡抬升,把握结构性行情
  • 特朗普将启的中东行会如何影响伊美核谈判?专家分析