前端内存泄漏总结

121 阅读4分钟

内存管理

想知道内存是怎么泄漏的,首先要明白js的内存是如何管理的

JavaScript 是在创建变量(对象,字符串等)时自动进行了分配内存,并且在不使用它们时“自动”释放。释放的过程称为垃圾回收。这个“自动”是混乱的根源,并让 JavaScript(和其他高级语言)开发者错误的感觉他们可以不关心内存管理。

内存生命周期

不管什么程序语言,内存生命周期基本是一致的:

  1. 分配你所需要的内存
  2. 使用分配到的内存(读、写)
  3. 不需要时将其释放\归还

所有语言第二部分都是明确的。第一和第三部分在底层语言中是明确的,但在像 JavaScript 这些高级语言中,大部分都是隐含的。

内存分配

  1. 值的初始化时分配内存,js在定义变量时就完成了内存分配
  2. 通过函数调用分配内存
值的初始化
var n = 123; // 给数值变量分配内存
var s = "azerty"; // 给字符串分配内存

var o = {
  a: 1,
  b: null,
}; // 给对象及其包含的值分配内存

// 给数组及其包含的值分配内存(就像对象一样)
var a = [1, null, "abra"];

function f(a) {
  return a + 2;
} // 给函数(可调用的对象)分配内存

// 函数表达式也能分配一个对象
someElement.addEventListener(
  "click",
  function () {
    someElement.style.backgroundColor = "blue";
  },
  false,
);

通过函数调用分配内存

有些函数调用结果是分配对象内存:

var d = new Date(); // 分配一个 Date 对象

var e = document.createElement("div"); // 分配一个 DOM 元素

有些方法分配新变量或者新对象:

var s = "azerty";
var s2 = s.substr(0, 3); // s2 是一个新的字符串
// 因为字符串是不变量,
// JavaScript 可能决定不分配内存,
// 只是存储了 [0-3] 的范围。

var a = ["ouais ouais", "nan nan"];
var a2 = ["generation", "nan nan"];
var a3 = a.concat(a2);
// 新数组有四个元素,是 a 连接 a2 的结果

使用值

使用值的过程实际上是对分配内存进行读取与写入的操作。读取与写入可能是写入一个变量或者一个对象的属性值,甚至传递函数的参数。

内存释放 就是垃圾回收

高级语言解释器嵌入了“垃圾回收器”,它的主要工作是跟踪内存的分配和使用,以便当分配的内存不再使用时,自动释放它。这只能是一个近似的过程,因为要知道是否仍然需要某块内存是无法判定的(无法通过某种算法解决)。

垃圾回收实现只能有限制的解决一般问题 刚开始时 浏览器大多使用引用计数垃圾收集算法,内存泄漏的很明显,后来又改进位标记-清楚算法

1、引用计数垃圾收集 限制是无法解决循环引用

2、标记-清除算法

标记清除算法的原理: 这个算法假定设置一个叫做根(root)的对象(在 Javascript 里,根是全局对象)。垃圾回收器将定期从根开始,找所有从根开始引用的对象,然后找这些对象引用的对象……从根开始,垃圾回收器将找到所有可以获得的对象和收集所有不能获得的对象。

最起码解决了循环引用的问题,但是依旧有限制:那些无法从根对象查询到的对象都将被清除

内存泄漏的一些案例

1、意外的全局变量

2、闭包

function closuer() {
	const b = 0
	return c => b + c
}

const render = closuer()

render()
render = null // 手动设置为null

3、定时器未清理 定时器也常会造成内存泄露

var someResource = getData();
setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
        // 处理 node 和 someResource
        node.innerHTML = JSON.stringify(someResource));
    }
}, 1000);

4、未正确解绑事件处理程序:

例如:在DOM元素上或者window上绑定的addEventListener在组件移除时没有取消绑定

image.png

5、使用缓存不当:

如果不适当地使用缓存,可能导致缓存的数据一直存在于内存中,即使不再需要。需要定期清理缓存或使用一些策略来确保合理使用缓存。

6、未释放资源:

例如,使用 XMLHttpRequest 发送请求时,如果没有正确处理和释放资源,可能会导致内存泄漏。确保在请求完成后正确关闭或释放资源。

7、DOM 元素引用:

在 JavaScript 中引用了 DOM 元素,但在页面生命周期结束前没有释放这些引用。在单页应用(SPA)中,注意在组件销毁时释放对 DOM 元素的引用。

8、大量数据未清理:

在处理大量数据时,确保及时清理不再需要的数据,以防止长时间占用内存。

参考链接:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Memory_management

参考链接:https://fe.ecool.fun/topic/cecf2aa7-4281-4255-95c9-e8ae487760f1?orderBy=default&order=desc&titleKey=%E5%86%85%E5%AD%98%E6%B3%84%E6%BC%8F

参考链接:https://blog.csdn.net/qq_17335549/article/details/135436565