今天给大家讲解一下我们面试时经常会碰到的一个问题——JS的垃圾回收机制。
垃圾回收是计算机编程中的一个术语,用来描述查找和删除那些不再被其他对象引用的对象的处理过程。换句话说,垃圾回收是删除任何其他对象未使用的对象的过程。
如果没有垃圾回收机制,那么对象将会一直占用系统中的可用内存,如果不释放掉这些内存的话,就将直接导致系统崩溃。
垃圾回收器
垃圾收集通常缩写为"GC",是JS中使用的内存管理系统的基本组成部分,它是靠浏览器中的垃圾回收器来回收处理的。
垃圾回收器是浏览器中的一个专门的线程,它每隔很短的时间就会运行一次,它主要作用是判断一个对象是否是垃圾对象,如果是,清除其内存数据,并标记内存是空闲状态。
判断垃圾对象
使用局部变量
functionfn(){vara=1;};fn();
当fn执行时,会创建a变量。此时在栈空间中会给他分配一块内存存储变量。
当fn执行结束后,由于不再需要变量a,所以此时的a就成为了垃圾变量。栈空间会立即释放之前给变量分配的内存。至此,垃圾回收完成。
使用对象
varobj={
name:"Tom",
age:"18",
};
obj=null;
当对象创建时,此时的变量obj指向堆内存开辟的一块空间。
当我们给obj重新赋值为null时,变量obj和堆内存之间的联系断开。
由于此时堆内存中的空间没有被引用,所以这块空间就成为了JS中所谓的垃圾。
可能成为垃圾的特例
全局变量:
由于全局变量window一般只在页面卸载时进行销毁,所以程序就很难对全局变量是否为垃圾对象进行判断。所以要尽量少声明全局变量,或者在使用完变量后重新赋值为null。
闭包:
由于闭包引用了外部函数的变量,所以当闭包被使用时,垃圾回收机制也无法对外层函数被引用的变量进行回收。所以需要手动把使用闭包的变量赋值为null。
回收策略
JS中垃圾回收机制的策略有两种:引用计数法和标记清除法。他们本质上都是找到未被引用的值,从而在垃圾回收执行时释放其空间。
引用计数法
概念:最初级的垃圾收集算法,现在已经不再使用,把“对象是否不再需要”简化定义为“对象有没有引用指向它”。
原理:每个对象内部都标记一下引用它的总个数,如果引用个数为0时,即为垃圾对象。
vara={}count=1
varb=acount=2
a=nullcount=1
b=nullcount=0//垃圾对象
缺点:有循环引用问题:如果2个对象内部存在相互引用,断开对象的引用后,它们还不是垃圾对象。
varo1={};count1=1
varo2={};count2=1
o1.m=o2count2=2
o2.n=o1count1=2
o1=nullcount1=1
o2=nullcount2=1
//2个对象的计数值都为1,所以他们都不是垃圾对象。
标记-清除法
概念:当前垃圾回收算法的基础,它“对象是否不再需要”简化定义为“对象是否可以获得”。
原理:从根对象(也就是window)开始查找所有引用的对象,并标记为‘使用中’,没有标记为使用中的对象就是垃圾对象。
优点:没有循环引用问题,循环引用的对象也可能是垃圾对象。
varo1={};
varo2={};
o1.a=o2;//o1引用o2
o2.a=o1;//o2引用o1
o1=null
o2=null
//通过window找不到这2个对象,它们就没有被标记为‘使用中’,就当作垃圾对象回收释放。
总结
简单来讲,在JS中,凡是未被引用的变量或对象,都会被视为垃圾。并且JS主要是通过目前使用的标记清除法实现垃圾回收。
我们在面试的时候可以先跟面试官解释一下在为什么要使用垃圾回收机制,在JS中什么是垃圾;然后再对两种垃圾回收策略进行说明,最后可以列举一下常见的内存泄露问题。
希望这篇文章能帮助到大家对垃圾回收机制有一个更加深入的理解,以后在面试时碰到这个问题也能侃侃而谈,稳操胜券。