v8引擎垃圾回收

V8引擎垃圾回收机制

v8引擎负责JavaScript的执行。V8引擎具有内置的垃圾回收机制,用于自动管理内存分配和释放

堆与栈

栈空间

栈空间是小而连续的内存空间,主要用于存储局部变量和函数调用的相关信息,同时栈结构是“先进后出”的策略

栈空间的最大的特点是空间连续,所以在栈中每个元素的地址都是固定的,因此栈空间的查找效率非常高,但是通常在内存中,很难分配到一块很大的连续空间,因此,V8 对栈空间的大小做了限制,如果函数调用层过深,那么 V8 就有可能抛出栈溢出的错误

  • 分配和释放速度快‌:栈上的资源分配和销毁只需要移动指针,因此速度非常快。
  • 固定大小‌:栈的空间是有限的,一旦函数调用层次过多或数据过大,就会导致栈溢出。
  • 遵循LIFO原则‌:后进先出,即最后进入栈的元素会被最先弹出。
堆空间

堆空间是一种形的存储结构,用来存储对象类型的离散的数据

  • 动态分配‌:堆上的内存空间是动态分配的,可以根据需要分配不同大小的内存块。
  • 灵活性高‌:堆可以存储各种类型的数据,包括对象、数组等复杂数据结构。
  • 管理复杂‌:由于堆的空间是动态分配的,管理起来相对复杂,容易出现内存泄漏等问题

回收策略

1》标记清除

这种算法在 JS 引擎中是最常用的(大部分浏览器都是V8引擎,使用的是标记清除)

大致过程:

首先标记内存中所有的变量(假设所有的都是垃圾,都标记为0);

然后将在上下文中的变量以及被上下文引用的变量的标记清除;

在此之后(离开环境时不再当前环境定义的变量被标记清除)的再被加上标记的变量就是待删除了

优点:

实现比较简单,打标记也无非打与不打两种情况,这使得一位二进制位(0和1)就可以为其标记,非常简单

缺点:

标记清除算法有一个很大的缺点,就是在清除之后,剩余的对象内存位置是不变的,也会导致空闲内存空间是不连续的,出现了 内存碎),并且由于剩余空闲内存不是一整块,它是由不同大小内存组成的内存列表,这就牵扯出了内存分配的问题

标记整理算法:在标记结束后,将活着的对象向内存的一端移动(将不需要清理的对象往内存一端移动),最后清理掉边界的内存

2》引用计数

大致过程:

声明变量并赋值的时候引用次数为1

当同一个值被赋值给另一个比那辆,引用书加1

如果对该值引用的变量被其他值覆盖了,引用书减1

如果引用次数为0时就可以被回收了

优点:

引用计数算法的优点我们对比标记清除来看就会清晰很多,首先引用计数在引用值为 0 时,也就是在变成垃圾的那一刻就会被回收,所以它可以立即回收垃圾

缺点:

首先它需要一个计数器,而此计数器需要占很大的位置,因为我们也不知道被引用数量的上限

其次,循环引用问题;对象A有一个指针指向对象B,而对象B也引用了对象A

对象A、B的引用次数都是2,在函数执行后,其实引用次数仍然时2;但是它们其实都不在作用域中了,属于可以回收的垃圾,但是内存并没有被释放

      function circleRef() {
        let A = new Object()
        let B = new Object()
        A.a = B
        B.b = A
      }
      circleRef()

想要释放必须在最后去掉引用关系

A=null
B=null

IE8及以前是使用的引用清除

V8引擎内存空间划分

‌**1》新生代(new space)**‌:用于存储新创建的对象。分为两部分,分别是‌使用去和空闲区

‌**2》老生代(old space)**‌:存储生存时间较长的对象。这些对象在新生代中存活一段时间后,会被移动到老生代。老生代内存区域相对较大,因为存储的是长期存活的对象,所以垃圾回收的频率相对较低。老生代内存区又分为老生代指针区和老生代数据区,前者包含大多数可能存在指向其他对象的指针的对象,后者只保存原始数据对象,这些对象没有指向其他对象的指针

‌**3》大对象区(Large Object Space)**‌:存放体积超过其他区域大小限制的大对象,这些对象由于体积较大,不会被频繁移动,因此放在单独的区域以避免影响其他对象的垃圾回收

‌**4》代码区(Code Space)**‌:存放JavaScript代码,这是唯一拥有执行权限的内存区域

‌**5》Map区(Map Space)**‌:用于存放Cell和Map,每个区域都是存放相同大小的元素,结构简单

6》Cell Space和Property Cell Space:用于存储固定大小的Cell对象和与JavaScript对象属性相关的PropertyCell对象,优化属性访问性能

V8引擎的垃圾回收策略

V8 设置了两个垃圾回收器,主垃圾回收器和副垃圾回收器;主垃圾回收器负责收集老生代中的垃圾数据,回收频率较低;副垃圾回收器负责收集新生代中的垃圾数据,回收相比更加频繁

可访问性分析法

V8引擎中采用了这种方法来判断是一个对象是否活跃,具体过程为:将一个称为GC Roots的对象(在浏览器环境中,GC Roots 可以包括:全局的 window 对象、所有原生DOM节点集合等等)作为所有初始存活的对象集合,从这个对象出发,进行遍历,遍历到的就认为是可访问的,为活动对象,需要保留;如果没有遍历到的对象,就是不可访问的,这些就是非活动对象,可能就会被垃圾回收。

新生代

新生代:主要用于存放存活时间较短的对象。使用scavenge算法进行回收

新生代回收过程:

scavenge算法主要使用了一种复制式的方法cheney算法(复制式的方法)来实现;

新生代空间被平等划分为两部分,from space 和to space; 当from space填满之后会进行一次垃圾回收,非存货对象被回收,存活的对象被复制到 to space,from space被清空,from space和to space进行了一次交换

scavenge算法是一种典型的牺牲空间换取时间的算法

新生代垃圾回收采用了并行机制。在新生代垃圾回收的过程中,副垃圾回收器使用并行机制,在整理排序阶段,即活动对象从from-space复制到to-space的时候,启用多个辅助线程并行进行整理。这种并行处理的方式意味着多个线程同时参与垃圾回收的过程,以提高效率。由于多个线程可能竞争同一个新生代的堆内存资源,可能会出现某个活动对象被多个线程进行复制操作的情况。为了解决这个问题,V8在第一个线程对活动对象进行复制完成后,必须去维护复制这个活动对象后的指针转发地址,以便于其他协助线程可以找到该活动对象后可以判断该活动对象是否已被复制。这种机制确保了新生代垃圾回收的正确性和效率‌

对象晋升(新生代变成老生代)

当一个对象在经过多次复制之后依旧存活,那么它会被认为是一个生命周期较长的对象,在下一次进行垃圾回收时,该对象会被直接转移到老生代中

晋升的条件:

  • 对象是否经历过一次Scavenge算法
  • 内存占比是否超过To空间的25%(避免内存使用过高影响后续的对象分配)

满足其中任意一个就会晋升

老生代

老生代采用Mark-Sweep(标记清除)Mark-Compact(标记整理)`来进行管理

老生代回收过程:

  1. 标记;递归遍历一组根元素,遍历能达到的元素是活动对象,达不到的是非活动对象 (Mark-Sweep)
  2. 清除;老生代垃圾回收器直接将非活动对象(数据、垃圾)清理掉 (Mark-Sweep)
  3. 整理;(Mark-Compact)

以下几种情况都可以作为根节点:

  1. 全局对象
  2. 本地函数的局部变量和参数
  3. 当前嵌套调用链上的其他函数的变量和参数

Mark-Sweep算法存在一个问题,就是在经历过一次标记清除后,内存空间可能会出现不连续的状态,因为我们所清理的对象的内存地址可能不是连续的,所以就会出现内存碎片的问题,导致后面如果需要分配一个大对象而空闲内存不足以分配,就会提前触发垃圾回收;所以通过Mark-Compact(标记整理)解决内存碎片的问题

一般 10 次Mark-Sweep会伴随一次Mark-Compact

策略优化

最开始的垃圾回收机制有两个大的缺点

  • 垃圾回收器在主线程上执行,执行垃圾回收期间会阻塞js执行
  • 一次执行一个完整的垃圾回收流程,阻塞时间还是连续的

对此V8做出了许多优化:

一般来说,老生代会保存大量存活的对象,如果在标记阶段将整个堆内存遍历一遍,那么势必会造成严重的卡顿。

因此,为了减少垃圾回收带来的停顿时间,V8引擎又引入了增量标记 的概念,即将原本需要一次性遍历堆内存的操作改为增量标记的方式,先标记堆内存中的一部分对象,然后暂停,将执行权重新交给JS主线程,待主线程任务执行完毕后再从原来暂停标记的地方继续标记,直到标记完整个堆内存。只有在浏览器的空闲时间才会执行对应的任务,否则延迟执行,尽可能少地影响主线程的任务,避免应用卡顿,提升应用性能。

得益于增量标记的好处,V8引擎后续继续引入了延迟清理 增量式整理,让清理和整理的过程也变成增量式的。同时为了充分利用多核CPU的性能,也将引入并行标记并行清理,进一步地减少垃圾回收对主线程的影响,为应用提升更多的性能

  • 增量标记:V8使用增量标记,即不是一次性遍历整个堆,而是分批次进行,使得每次正常执行之间的停顿非常短暂;即将原本需要一次性遍历堆内存的操作改为增量标记的方式,先标记堆内存中的一部分对象,然后暂停,将执行权重新交给JS主线程,待主线程任务执行完毕后再从原来暂停标记的地方继续标记,直到标记完整个堆内存
  • 延迟清理:在浏览器的空闲时间执行垃圾回收任务
  • 增量整理:一次整理一部分
  • 并发标记:允许垃圾回收的标记阶段与JavaScript代码执行并行进行,减少了主线程的暂停时间
  • 并行处理:多个辅助线程并行进行整理,提高了垃圾回收的效率

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/943218.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[按键精灵IOS安卓版][脚本基础知识]按键post基本写法

这一期我们来讲按键post的写法,希望通过本期的学习,实现常见的post提交都能编写。 下面开始讲解: 一、使用的命令:url.httppost 选用这个命令的理由是它的参数比较全。 二、post请求都有哪些参数(可能用到&#xf…

如何检查交叉编译器gcc工具链里是否有某个库(以zlib库和libpng库为例)

freetype 依赖于 libpng,libpng 又依赖于 zlib,所以我们应该:先编译 安装 zlib,再编译安装 libpng,最后编译安装 freetype。 但是,有些交叉编译器工具链里已经有 zlib库和freetype,所以我们需要…

3D几何建模引擎Parasolid功能解析

一、什么是Parasolid? Parasolid是由Siemens PLM Software开发的高精度精密几何建模引擎。它全面评估CAD(计算机辅助设计)、CAM(计算机辅助制造)、CAE(计算机辅助工程)、PLM(产品生…

基于STM32单片机矿井矿工作业安全监测设计

基于STM32单片机矿井矿工作业安全监测设计 目录 项目开发背景设计实现的功能项目硬件模块组成设计思路系统功能总结使用的模块技术详情介绍总结 1. 项目开发背景 随着矿井矿工作业环境的复杂性和危险性逐渐增加,矿井作业安全问题引起了社会各界的广泛关注。传统的…

linux-22 目录管理(二)rmdir命令,删除目录

那接下来我们来看看我们如何去删除目录?那接下来我们来看看我们如何去删除目录?叫remove,remove表示移除的意思,remove directory叫移除目录。所以简写为rmdir,但需要注意,它只能删除空目录,只能…

计算机考研选西电还是成电?

谢邀~先来个总结:电子科技大学计算机综合实力优于西安电子科技大学,但是,二者计算机学硕考研难度没有太大差距,而且考试难度也同属于一个水平,成电性价比更高一些!推荐同学优先报考作为985的电子科技大学&a…

基于YOLOV5+Flask安全帽RTSP视频流实时目标检测

1、背景 在现代工业和建筑行业中,安全始终是首要考虑的因素之一。特别是在施工现场,工人佩戴安全帽是确保人身安全的基本要求。然而,人工监督难免会有疏漏,尤其是在大型工地或复杂环境中,确保每个人都佩戴安全帽变得非…

oscp学习之路,Kioptix Level2靶场通关教程

oscp学习之路,Kioptix Level2靶场通关教程 靶场下载:Kioptrix Level 2.zip 链接: https://pan.baidu.com/s/1gxVRhrzLW1oI_MhcfWPn0w?pwd1111 提取码: 1111 搭建好靶场之后输入ip a看一下攻击机的IP。 确定好本机IP后,使用nmap扫描网段&…

yii2 手动添加 phpoffice\phpexcel

1.下载地址:https://github.com/PHPOffice/PHPExcel 2.解压并修改文件名为phpexcel 在yii项目的vendor目录下创建一个文件夹命名为phpoffice 把phpexcel目录放到phpoffic文件夹下 查看vendor\phpoffice\phpexcel目录下会看到这些文件 3.到vendor\composer目录下…

弹性盒子(display: flex)布局超全讲解|Flex 布局教程

文章目录 弹性盒子flex什么是弹性布局?弹性布局的特点?justify-contentalign-itemflex-direction (主轴的方向:水平或者垂直)flex-wrapflex-flowalign-contentflex-grow 属性flex-shrink 属性flex-basis 属性flex 属性align-self 属性 弹性盒…

基于c语言的union、字符串、格式化输入输出

结构体之共用体union 共用体也叫联合体,其关键词为union 与结构体不同的是,共用体所开辟的存储空间仅仅为其中最长类型变量的存储空间而不是全部变量的存储空间,由于同一内存单元在同一时间内只能存放其中一种的数据类型,因此在每…

【全栈开发】----用pymysql库连接MySQL,批量存入

本文基于前面的MySQL基础语句使用,还不会的宝子可以先回去看看: 全栈开发----Mysql基本配置与使用-CSDN博客 仅仅用控制台命令对数据库进行操作,虽然大部分操作都很简单,但对于大量数据的存入,存储数据将会变得很繁琐&…

PyQt实战——使用python提取JSON数据(十)

系类往期文章: PyQt5实战——多脚本集合包,前言与环境配置(一) PyQt5实战——多脚本集合包,UI以及工程布局(二) PyQt5实战——多脚本集合包,程序入口QMainWindow(三&…

51单片机学习笔记——找不到REG52.H头文件,点亮一个LED

创建工程 将STC型号导入keil并使用 STC可以从官网下载,也可我这的网盘: 链接:https://pan.baidu.com/s/1bO85DPN3IFaXGhiKSwyOrA?pwd7f4h 提取码:7f4h 打开STC,选择“keil仿真设置”,选择“添加型号和头…

windows和mac共享文件夹访问教程

mac共享文件夹,windows访问: mac上开启文件夹共享,并添加文件夹和用户,然后windows 上 在windows上快捷键 win r 打开运行,按如下格式输入mac设备的IP地址: 就可以访问了: windows共享文件夹…

webauthn介绍及应用

1、webauthn介绍 官网:https://webauthn.io/ 1.1、什么是webauthn? webauthn即Web Authentication,是一个符合W3C标准的Web认证规范。它通过公私钥加密技术,实现无密码认证,用户仅需通过pin码、指纹、面部识别、usb …

iOS AccentColor 和 Color Set

AccentColor 和 Color Set 都是 Xcode 中用于颜色管理的功能,它们适用于不同的开发场景和需求。以下是它们的区别和应用场景分析: 1. AccentColor(强调色) 1.1 概念: • AccentColor 是在 Xcode 12 中引入的&#xf…

TiDB 的MPP架构概述

MPP架构介绍: 如图,TiDB Server 作为协调者,首先 TiDB Server 会把每个TiFlash 拥有的region 会在TiFlash上做交换,让表连接在一个TiFlash上。另外 TiFlash会作为计算节点,每个TiFlash都负责数据交换,表连接…

git回退指定版本/复制提交id

1.使用“git reset --hard 目标版本号”命令将版本回退2.使用“git push -f”提交更改 因为我们回退后的本地库HEAD指向的版本比远程库的要旧,此时如果用“git push”会报错。 改为使用 git push -f 即可完成回退后的提交。

本地部署 LLaMA-Factory

本地部署 LLaMA-Factory 1. 本地部署 LLaMA-Factory2. 下载模型3. 微调模型3-1. 下载数据集3-2. 配置参数3-3. 启动微调3-4. 模型评估3-5. 模型对话 1. 本地部署 LLaMA-Factory 下载代码, git clone https://github.com/hiyouga/LLaMA-Factory.git cd LLaMA-Facto…