一. 简述
前端垃圾回收机制是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无法被垃圾回收机制回收
定时器
当使用setInterval或setTimeout函数时,如果没有清除定时器,定时器会一直运行,从而导致内存泄漏。
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如果没有及时清除,也会导致内存泄漏