内存泄漏

# 内存泄漏
# 内存生命周期
- 分配期:分配所需要的内存
- 使用期:使用分配到的内存(读、写)
- 释放期:不需要时将其释放和归还
# js 内存管理机制
- 内存自动分配
- 内存回收:垃圾内存回收(GC)
- 内存泄漏多发生在此阶段
# 垃圾回收算法
- 引用计数垃圾收集:对象有没有其他引用到他(零引用),对象被垃圾机制回收
- ES6 把引用区分为强引用和弱引用,Set Map
- 强引用会有引用计数叠加,只有引用计数为 0 的对象才会被回收,需手动回收
- 弱引用没有触发引用计数叠加,只要引用计数为 0,其会自动消失,无需手动回收内存
- 标记清除法:
- 当变量进入执行环境标记为“进入环境”
- 当变量离开执行环境则标记为“离开环境”
- 标记为“离开环境”的变量可被回收
- 环境可理解为作用域,但全局作用域的变量会在页面关闭后被销毁
# js 中内存泄漏的场景
意外的全局变量
被遗忘的计时器
setInterval和clearInterval
被遗忘的监听事件
window.addEventListener和window.removeEventListener
被遗忘的 ES6 Set 成员
let map = new Set(); let val = { test: 22 }; map.add(val); map.delete(val); val = null; let wap = new WeakSet(); let va = { test: 20 }; map.add(va); va = null;1
2
3
4
5
6
7
8
9
10
被遗忘的 ES6 Map 键名
let map = new Map(); let k = new Array(5 * 1024 * 1024); map.set(k, 1); map.delete(k); k = null; let wap = new WeakMap(); let key = new Array(5 * 1024 * 1024); wap.set(key, 1); key = null;1
2
3
4
5
6
7
8
9
10
被遗忘的订阅发布事件监听器
customEvent.emit("test", { type: "click" }); customEvant.on("test", (data) => {}); customEvant.off("test");1
2
3
4
5
被遗忘的闭包
function closure() { const name = "lisi"; return () => { return name.split(""); }; } const rename = closure(); rename();1
2
3
4
5
6
7
8
脱离的 DOM 引用
this.elements = { button: document.querySelector("#button"), }; document.body.removeChild(this.elements.button); this.elements.button = null;1
2
3
4
5
6
# 如何发现内存泄漏
- 确定是否存在内存泄漏问题
- 谷歌开发工具,切换至 Performance,勾选Memory,多次录制页面运行时,内存使用情况并分析
- 定位内存泄漏位置
- Snapshot-> Shallow Size逆序排序,查找内存占用最大者
上次更新: 2021/04/22, 00:08:06