• 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算法
      • 分代回收
      • 空间复制
      • 标记清除
      • 标记整理
      • 标记增量
  • 相关阅读:
    解决百度云大文件不能被其他下载器下载
    python中IndentationError: expected an indented block错误的解决方法
    2017Windows下安装pip
    α-β剪枝算法的java语言实现(非常实用)
    flask+sqlite3+echarts2+ajax数据可视化
    flask+sqlite3+echarts2+ajax数据可视化报错:UnicodeDecodeError: 'utf8' codec can't decode byte解决方法
    Windows下快速安装Flask的一次经历
    决策树ID3算法的java实现(基本适用所有的ID3)
    继续上篇抢QQ口令红包,抢那招抢不了的红包技巧
    【QQ红包】手机发抢不到的口令红包
  • 原文地址:https://www.cnblogs.com/xiaorong-9/p/13970214.html
Copyright © 2020-2023  润新知