消除 Javascript 中的内存泄漏
垃圾收集语言中泄漏的主要原因是不需要的引用。要了解内存泄漏,让我们看看内存释放(垃圾收集)的工作原理。
标记和清除算法 −此算法将"不再需要对象"的定义简化为"对象无法访问"。此算法假设知道一组称为根的对象。在 JavaScript 中,根是全局对象。GC 定期从这些根开始,递归查找从这些根引用的所有对象。从根开始,GC 将找到所有可访问的对象并收集所有不可达的对象。
内存泄漏的类型
1.全局变量(未声明/意外)
在 JS 中,如果您未指定声明关键字(let、var、const),则可以意外地全局声明变量。JS 查找范围外的变量,直到到达全局范围,如果在任何范围内都找不到该变量,则会创建一个全局变量。
示例
function test() { a = [1, 2, 3] } test() // a 未使用关键字声明就进行了初始化,现在位于全局范围内。 console.log(a)
输出
[1, 2, 3]
此行为可能会导致内存泄漏,因为变量在不知不觉中存在于全局范围内,除非程序结束,否则不会被释放。可以使用声明关键字来修复此问题。
2. 闭包
如果在外部函数中声明了一个变量,并且该变量自动可供嵌套的内部函数使用,并且即使未在嵌套函数中使用/引用该变量,它仍会继续存在于内存中,则闭包中会发生内存泄漏。
3. 分离的 DOM/DOM 外引用
DOM 是双向链接树,引用树中的任何节点都会阻止整棵树进行垃圾回收。分离的 DOM 或 DOM 外引用意味着已从 DOM 中删除但通过 JS 存在于内存中的节点。这意味着只要任何地方仍有对变量或对象的引用,即使从 DOM 中删除该对象也不会被垃圾回收。完成 DOM 的一部分后,请务必从 JS 中删除引用。
4.事件监听器
addEventListener() 方法将事件处理程序附加到元素,并且可以将多个事件处理程序添加到单个元素。如果 DOM 元素及其事件监听器没有相同的生命周期,则可能导致内存泄漏。