javaScript中的垃圾回收机制

在这之前先了解下什么是js中的垃圾?对于前端开发来说,js中内存管理是自动的,当创建对象、数组、函数等时就会自动给分配空间,当后续代码开发过程中对象不再被引用,或者不能从根上访问到时(不可达对象)这些都被称为垃圾。(javascript 中的根可以理解为是全局变量对象)

这里用到了可达对象这个词,那么js中的可达对象是什么?

​ 可以访问到的对象就是可达对象(通过引用、作用域链),可达的标准就是从根出发能够被找到

GC

就是垃圾回收机制的简写,可以找到内存中的垃圾、并释放和回收空间。

GC里的垃圾是什么

  • 程序中不再使用的对象
function fn(){
	name='lj'
	return `GC里的${name}是不再使用的对象`
}
fn()
当函数调用完成后,name变量不在被其他地方使用到。
  • 程序中不能再访问到的对象
function fn(){
	const name='lj'
	return `GC里的${name}是不能访问到的对象`
}
fn()
name只能在fn函数内部访问,当fn 函数调用完成后,name 就成为不能再被访问的对象。

GC算法是什么

算法就是垃圾回收器在工作时查找和回收所遵循的规则。

常见的GC算法

  1. 引用计数

    核心思想:通过引用计数器来维护引用数。设置引用数,判断引用计数是否为0;当引用关系发生改变时,引用计数器就会修改引用数字,当引用数字为0时,GC会立即工作将当前的对象空间进行回收。

    const a=100;
    const b=20;
    const arr=[a,b];
    function fn(){
    	const num = 0;
    }
    fn()
    

    从上面这段代码的执行来分析,代码执行完毕后,fn函数中的常量num 的引用数字会为0,常量a,b还在被arr 使用,所以他们的引用数字肯定不是0,那么当整段代码执行完毕后,只有num 计数为0,它就会被当做垃圾进行清理。

    优点:

    • 发现垃圾时立即回收(数字为0),将内存立即释放
    • 时刻监听着是否有垃圾,内存也就不会占满,最大限度减少程序卡顿时间

    缺点:

    • 无法回收循环引用的对象(计数永远不为0所以不能被回收)
    • 时间开销大
    //循环引用的对象  计数算法缺点
    function fn(){
    	const obj1={}
    	const obj2={}
    	obj1.name=obj2
    	obj2.name=obj1
    }
    fn()
    

    当上面的代码执行完成后,fn 函数内部的obj1 和obj2 在外部就不能被访问到了,按照GC里的垃圾概念,其就可以视为垃圾被清除掉。但是从 引用计数算法来说 obj1 和obj2 的引用次数都不为0,使用引用计数算法的话,他们是不会被视为垃圾被清理的。

  2. 标记清除

    核心思想:分标记和清除两个阶段完成,第一阶段会遍历所有的对象找到活动对象(也称为可达对象),第二阶段仍是遍历所有的对象,清除没有被标记的对象,回收相应的空间并清除所有标记。同时它会将回收的空间放在空闲列表中,方便后续程序在这个中申请空间使用。

    优点:

    • 相对于计数算法来说,解决了循环引用的对象不能被回收的缺点。

    缺点:

    • 空间碎片化(由于回收的垃圾对象在地址上是不连续的,分散在各个地方,当我们使用的时候可能会遇到空间大或者空间小的问题,使我们的空间不能得到最大化的使用。)
  3. 标记整理

    核心思想:标记整理算法可以说是标记清除的增强,第一阶段与标记清除算法一致,第二阶段清除未标记对象前,会先执行整理,移动对象的位置,使回收的空间产生连续。

    红色代表活动对象 棕色代表非活动对象 白色代表剩余空间。标记整理算法的整个过程如下图:

  4. 分代回收

    这个算法思想在V8的垃圾回收策略中被使用。这里我们先来了解下什么是V8.

    认识V8

    • v8是一款主流的JavaScript 执行引擎
    • v8采用即时编译
    • v8内存设置上限
    • v8采用基于分代回收思想实现垃圾回收
    • v8内存分为新生代和老生代
    V8的垃圾回收策略

    采用分代回收的思想,将内存空间一分为二,左侧新生代(新生代指的是存活时间较短的对象,小空间用于存储新生代对象(32M|16M)(64位|32位)),右侧老生代(老生代指的是存活时间较长的对象 。64位操作系统1.4G,32位操作系统700M),,针对不同的部分采用不同的算法。

    V8中新生代存储区垃圾回收的流程
    • 回收过程采用复制算法+标记整理
    • 新生代内存区分为二个等大小空间 , From 状态和To状态的两个空间
    • 使用空间为From,空闲空间为To
    • 如果代码在执行的时候需要申请空间使用,就会将所有的变量对象存储于From空间
    • 当from空间使用空间量达到一定程度后,GC就会启动开始标记整理后(活动对象全部找到,进行整理)将活动对象拷贝至To空间
    • 将From空间完成释放
    V8如何回收老生代对象
    • 主要采用标记清除、标记整理、增量标记算法
    • 首先使用标记清除完成垃圾空间的回收
    • 采用标记整理进行空间优化(当新生代对象晋升,需要移动到老生代对象中,出现空间不足的情况)
    • 采用增量标记进行效率优化
    对比:
    • 新生代区域垃圾回收使用空间换时间
    • 老生代区域垃圾回收不适合复制算法
    V8中常用的GC算法
    • 分代回收
    • 空间复制
    • 标记清除
    • 标记整理
    • 标记增量
posted on 2020-11-13 16:52  你是我支撑下去的理由  阅读(198)  评论(0编辑  收藏  举报