v8实现原理

js引擎

为什么需要js引擎

高级编程语言都要转化为最终的机械指令来执行
我们平时编写的js,无论交给浏览器或Node执行,最终都需要被CPU执行
CPU只认识自己的指令集(机械语言只包含0和1)能被CPU执行
需要js引擎将js代码翻译成CPU指令来执行

常见js引擎

SpiderMonkey:第一款js引擎,js作者开发
Chakra:IE浏览器,微软开发
JavaScriptCore:WebKit,Apple公司开发
V8:Google,Google开发

垃圾回收机制可看
https://zhuanlan.zhihu.com/p/390563834
https://www.cnblogs.com/12345huangchun/p/10217342.html

V8工作原理
https://blog.csdn.net/qq_45644850/article/details/118895975
https://blog.csdn.net/qq_44482048/article/details/124692787
V8如何垃圾回收
https://blog.csdn.net/qq_53225741/article/details/125330813

从栈中回收

js引擎通过向下移动ESP销毁该函数保存在栈中的执行上下文
在这里插入图片描述
showName函数执行结束后,ESP向下移动到foo函数的执行上下文中,上面showName的执行上下文虽然保存在栈内存中,但已经为无效内存了,如当foo函数再次调用另外一个函数时,该内容会直接覆盖掉,用来存放另一个函数的执行上下文。

从堆中回收

V8中会把堆分为两个区域
新生代(存放生存时间短的对象)通常只支持1-8m的容量
老生代(存放生存时间久的对象)支持容量比新生代大很多
V8分别使用两个不同垃圾回收器
副垃圾回收器:主要负责新生代的垃圾回收
主垃圾回收器:主要负责老生代的垃圾回收。

不论什么类型的垃圾回收器,都有一套共同的执行流程

  1. 标记空间中活动对象(还在使用的对象)和非活动对象(可进行垃圾回收的对象)
  2. 回收非活动对象所占据的内存。即在完成所有标记后,统一清理内存中所有被标记为可回收的对象
  3. 内存整理。频繁回收对象后,内存中会存在大量不连续空间,即内存碎片。内存中出现大量内存碎片时,可能会导致后期分配内存时出现内存不足情况。
    注意:副垃圾回收器不会产生内存碎片
    在这里插入图片描述

新生代(生存时间短)副垃圾回收器

算法:Scavenge算法
原理

  1. 把新生代空间对半划分为两个区域,对象区域空闲区域
  2. 新加入的对象存放在对象区域,对象区域快被写满时,需要执行一次垃圾清理操作
  3. 先对对象区域中的垃圾做标记,标记完成后,把这些存活的对象 复制到空闲区域
  4. 完成复制后,对象区域和空间区域进行角色翻转,也就是原来的对象区域变成空闲区域,原来的空闲区域变成对象区域

为什么新生代的空间会被设置得比较小?
由于新生代中采用的 Scavenge 算法,所以每次执行清理操作时,都需要将存活的对象从对象区域复制到空闲区域。
但复制操作需要时间成本,如果新生区空间设置得太大,会导致每次清理的时间就会过久,所以为了执行效率,一般新生区的空间会被设置得比较小。

也正是因为新生区的空间不大,所以很容易被存活的对象装满整个区域。为了解决这个问题,JavaScript 引擎采用对象晋升策略

对象晋升策略:经过两次垃圾回收依然存活的对象,会移动到老生代区中

老生代(生存时间久)主垃圾回收器

算法:标记 - 清除(Mark-Sweep)算法
原理

  1. 标记:标记阶段从一组根元素开始,递归遍历这组元素,在这个遍历过程中,能到达的元素称为活动元素(如某块数据被一个变量b引用了,那么这款数据会被标记为活动对象)没有到达的元素可判断为垃圾数据
  2. 清除:清除垃圾数据
    在这里插入图片描述

碎片:对一块内存多次执行标记 - 清除算法后,会产生大量不连续的内存碎片。碎片过多导致大对象无法分配到足够的连续内存

算法:标记 - 整理(Mark-Compact)算法
标记过程和标记 - 清除算法一样。后续步骤不是直接对可回收对象进行清理,是让所有存活的对象都向一端移动,然后直接清理调端边界以外的内存
在这里插入图片描述

优化算法:增量标记(Incremental Marking)算法
原理

  1. 为降低老生代的垃圾回收造成的卡顿
  2. V8把一个完整的垃圾回收任务拆分为很多小的任务
  3. 让垃圾回收标记和JavaScript应用逻辑交替进行直到标记阶段完成
    在这里插入图片描述
    全停顿
    V8使用主副垃圾回收器进行垃圾回收,由于js是运行在主线程之上,一旦执行垃圾回收算法,最终都需将正在执行的JavaScript脚本暂停,待垃圾回收完毕后再恢复脚本执行
    在这里插入图片描述

V8如何执行一段JavaScript代码

在这里插入图片描述
V8执行一段代码流程
在这里插入图片描述
在这里插入图片描述
生成抽象语法树(AST)和执行上下文
执行上下文主要是代码在执行过程中的环境信息,AST可看成代码结构化的表示。AST的生成过程,先分词(词法分析)再解析(语法分析)

AST是一种非常重要的数据结构,有广泛的应用。
babel(将es6转为es5)工作原理:先将es6源码转换为AST,将es6语法的AST转为es5语法的AST,最后利用es5的AST生成JavaScript源代码。
eslint(检查JavaScript编写规范的插件)检测流程:需要将源码转化为AST,利用AST检查代码规范化的问题

生成字节码(解释器)
字节码就是介于AST和机器码之间的一种代码,与特定类型的机器码无关,字节码需要通过解释器将其转换为机器码后才能执行

执行代码
解释器lgnition除了负责生成字节码外,还有另一个作用,解释执行字节码。如果有一段第一次执行的字节码,解释器lgnition会逐条解释执行,在lgnition执行字节码过程中,如果发现有热点代码(HotSpot)如一段代码被重复执行多次,这种就时热点代码,那么后台的编译器TurboFan会把该段热点的字节码编译为高效的机器码,当再次执行这段被优化的代码时,只需执行编译后的机器码即可。提升代码执行效率

补充:Ignition->点火器,TurboFan->螺旋增压,寓意着代码启动时通过点火器慢慢发动,一旦启动,涡轮增压介入,其执行效率随着执行时间越来越高。

为什么转为字节码不是机器码
js执行的环境不固定,可能是Windows,Mac,Linux,Node.js,不同环境中有不同CPU,不同CPU有不同CPU架构,不同架构能执行的机器指令不一样

即时编译技术JIT
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值