内存管理
想知道内存是怎么泄漏的,首先要明白js的内存是如何管理的
JavaScript 是在创建变量(对象,字符串等)时自动进行了分配内存,并且在不使用它们时“自动”释放。释放的过程称为垃圾回收。这个“自动”是混乱的根源,并让 JavaScript(和其他高级语言)开发者错误的感觉他们可以不关心内存管理。
内存生命周期
不管什么程序语言,内存生命周期基本是一致的:
- 分配你所需要的内存
- 使用分配到的内存(读、写)
- 不需要时将其释放\归还
所有语言第二部分都是明确的。第一和第三部分在底层语言中是明确的,但在像 JavaScript 这些高级语言中,大部分都是隐含的。
内存分配
- 值的初始化时分配内存,js在定义变量时就完成了内存分配
- 通过函数调用分配内存
值的初始化
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在组件移除时没有取消绑定
5、使用缓存不当:
如果不适当地使用缓存,可能导致缓存的数据一直存在于内存中,即使不再需要。需要定期清理缓存或使用一些策略来确保合理使用缓存。
6、未释放资源:
例如,使用 XMLHttpRequest 发送请求时,如果没有正确处理和释放资源,可能会导致内存泄漏。确保在请求完成后正确关闭或释放资源。
7、DOM 元素引用:
在 JavaScript 中引用了 DOM 元素,但在页面生命周期结束前没有释放这些引用。在单页应用(SPA)中,注意在组件销毁时释放对 DOM 元素的引用。
8、大量数据未清理:
在处理大量数据时,确保及时清理不再需要的数据,以防止长时间占用内存。
参考链接:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Memory_management
参考链接:https://blog.csdn.net/qq_17335549/article/details/135436565