前端垃圾回收机制

1,243 阅读3分钟

一. 简述

前端垃圾回收机制是JavaScript的一个重要特性。由于JavaScript是一种动态类型语言,因此可能存在内存泄漏变量生命周期不可预测等问题。为了解决这些问题,垃圾回收机制应运而生。

二. 核心

垃圾回收机制的核心思想是自动寻找不再使用的对象,并且释放它们的内存空间。这样可以避免程序运行过程中占用过多内存,从而提高程序的性能和稳定性。

三. 分类

垃圾回收机制主要分为两种类型:标记清除引用计数。其中,标记清除是目前使用最为广泛的垃圾回收方法。

标记清除

标记清除机制通过标记所有活跃对象来工作。当程序申请新的内存时,内存管理器会首先遍历所有已有的对象,将不再使用的对象打上标记。然后,内存管理器将所有未被标记的对象释放掉,从而回收内存空间。

举例说明: 下面例子创建两个对象a和b,并分别互相引用。然后,将a和b分别置为null。这时,标记清除会遍历所有对象,并标记活跃对象。由于a和b已经没有任何引用了,它们将被打上垃圾回收的标记。最后,内存管理器会释放掉这两个对象所占用的内存空间。

let a = { name: '张三' };
let b = { name: '李四' };
a.friend = b;
b.friend = a;
a = full;
b = full;

引用计数

引用计数机制通过维护一个引用计数器来工作。每当有一个新的引用指向某一个对象时,引用计数器就会加1。当某个对象的引用计数器为0时,说明该对象已经不再使用,可以进行回收。 引用计数机制的缺点是:无法循环处理引用的情况。例如,如果两个对象相互引用,它们的计数器永远不可能为0,从而导致内存泄漏的问题。

举例说明: 下面例子将obj赋值给obj1和obj2,obj的引用计数加2。当我们将obj1和obj2都置为null时,obj的引用计数减2,此时obj的引用计数为0,说明该对象已经不再被引用,可以被回收。

//创建一个对象
var obj = { name: '张三' };

//将obj的值赋值给obj1和obj2
var obj1 = obj;
var obj2 = obj;

//此时obj的引用计数为2

//将obj1和obj2的引用置为null
obj1 = null;
obj2 = null;

//此时obj的引用计数为0,可以被回收

四. 常见的JS内存泄漏

闭包

当函数内部定义了一个函数,并且内部函数引用了外部函数的变量,导致外部函数的变量无法被垃圾回收机制回收,从而造成内存泄漏。

function outer(){
    var name='张三';
    function inner(){
        console.log(name);
    }
    return inner;
}
var innerFunc=outer();
//inner函数引用了outer函数中的变量name,导致name无法被垃圾回收机制回收

定时器

当使用setIntervalsetTimeout函数时,如果没有清除定时器,定时器会一直运行,从而导致内存泄漏。

var timer=setInterval(function(){
    console.log('Hello World!');
},1000)
//setInterval()每隔一秒输出一次'Hello World!',如果没有清除定时器,定时器会一直运行,导致内存泄漏

DOM元素

当使用document.creatElement创建DOM元素时,如果没有及时从DOM树中删除该元素,会导致内存泄漏。

var element = document.creatElement('div');
document.body.appendChild(element);
//创建的div元素并将其添加到body元素中,如果没有从DOM树中删除该元素,会导致内存泄漏

全局变量

当定义了全局变量时,如果没有及时清除该变量,会导致内存泄漏。

var name='张三';
//定义的全局变量name如果没有及时清除,也会导致内存泄漏