JavaScript-V8引擎
一、浏览器内核-渲染引擎
渲染就是根据描述或者定义构建一个数据模型,生成图形的过程。
浏览器内核就是将页面(Html、Css、JavaScript)构建成可视化、可听化的多媒体结果。
我们也可以将浏览器内核称之为"渲染引擎",渲染引擎经常做的事情就是将Html、Css、JavaScript文本或者其他的资源文件转换成我们浏览器网页。
二、JavaScript引擎
2.1JavaScript引擎(JavaScript Engine)
当我们在执行一段代码时,真正赋予这段代码生命的就是JavaScript引擎(JavaScript Engine)。JavaScript引擎是一个专门处理JavaScript脚本的虚拟机,一般会附带在网页浏览器之中。
JavaScript引擎有许多种:
V8 — 开源,由 Google 开发,用 C ++ 编写。
Rhino — 由 Mozilla 基金会管理,开源,完全用 Java 开发。
SpiderMonkey — 是第一个支持 Netscape Navigator 的 JavaScript 引擎,目前正供 Firefox 使用。
JavaScriptCore — 开源,以Nitro形式销售,由苹果为Safari开发。
KJS — KDE 的引擎,最初由 Harri Porten 为 KDE 项目中的 Konqueror 网页浏览器开发。
Chakra (JScript9) — Internet Explorer。
Chakra (JavaScript) — Microsoft Edge。
Nashorn, 作为 OpenJDK 的一部分,由 Oracle Java 语言和工具组编写。
JerryScript — 物联网的轻量级引擎。
而最为大家熟知的无疑是V8引擎,他用于Chrome浏览器和Node中。
JavaScript引擎从头到尾负责整个JavaScript程序的编译和执行过程。
2.2渲染引擎和JavaScript引擎的关系
渲染引擎通过调用接口来处理JavaScript的逻辑。
JavaScript引擎通过桥接接口来访问渲染引擎的DOM、CSSDOM等。
2.3JavaScript引擎如何工作?
JavaScript引擎主要组成部分:
编译器:负责语法分析和代码生成。
解析器:负责接收字码节和解析执行字码节。
JIT工具:将字码节或者抽象语法树转换为本地代码(可执行代码)。
垃圾回收器和分析工具(Profiler):负责垃圾回收和收集引擎中的信息,帮助改善引擎的性能和功效。
JavaScript本质上是一种解释型语言,与编译型语言不同的是它需要一遍执行一边解析,而编译型语言在执行时已经完成编译,可直接执行,有更快的执行速度。
三、JavaScript-V8引擎的编译和执行
3.1数据表示
基本数据类型:Boolean、Number、String、Null、Undefined、Symbol、BigInt(起草第二阶段,但是以后在JavaScript中使用时板上钉钉的事情了)
对象类型(Array、Object、Date、Error等等)。 在V8中,数据表示分为两部分:
数据的实际内容,它们是变长的,而且内容的类型也不一样。
数据的句柄,大小是固定的,包含指向第一部分数据的指针。
3.2句柄Handle
V8需要进行垃圾回收,并需要移动这些数据内容,如果直接使用指针的话就会出问题或者需要比较大的开销。使用句柄就不存在这些问题,只需要修改句柄中的指针即可,使用者使用的还是句柄,它本身没有发生变化。
3.3内存堆和调用栈
mory Heap(内存堆) — 内存分配地址的地方
Call Stack(调用栈) — 代码执行的地方
3.3编译执行过程
四、V8内存分配
4.1小内存区块Zone类
管理一系列的小块内存,这些小内存的生命周期类似,可以使用一个Zone对象。 Zone对象先对自己申请一块内存,然后管理和分配一些小内存。当一块小内存被分配之后,不能被Zone回收,只能一次性回收Zone分配的所有小内存。例如:抽象语法树的内存分配和使用,在构建之后,会生成本地代码,然后其内存被一次性全部收回,效率非常高。
但是有一个严重的缺陷,当一个过程需要很多内存,Zone将需要分配大量的内存,却又不能及时回收,会导致内存不足情况。
4.2堆内存
V8使用堆来管理JavaScript使用的数据、以及生成的代码、哈希表等。为了更方便地实现垃圾回收,同很多虚拟机一样,V8将堆分成三个部分。年轻代、年老代、和大对象。
五、V8的垃圾回收机制
5.1新生代Scavenge(清除)算法
主要采用Cheney(人名)算法。一种采用复制的方式实现的垃圾回收算法。
1、将新生代堆内存分一为二,每一部分空间称为semispace。其中一个处于使用之中的称为from空间,另一个处于闲置称为to空间。
2、当我们分配对象时,先是在From空间中进行分配。
3、垃圾回收时,检查from空间内的存活对象,一是否经历过清除回收,二to空间是否已经使用了25%(保证新分配有足够的空间)。
4、将这些存活对象复制到to空间中。非存活对象占用的空间将会被释放。
5、完成复制后,from空间与to空间角色发生对换。
注:实际使用的堆内存是新生代中的两个semispace空间大小,和老生代所用内存大小之和。
如何判断对象是否存活呢?作用域?是一套存储和查询变量的规则。这套规则决定了内存里对象能否访问。
特点:清除算法是典型的牺牲空间换取时间的算法,无法大规模地应用到所有回收中,却非常适合应用在新生代生命周期短的变量。
5.2Mark-Sweep老生代标记清除
1、 标记阶段遍历堆中的所有对象,并标记活着的对象
2、 清除阶段,只清除没有被标记的对象。
最大的问题是,在进行一次标记清除之后会出现不连续的状态。这种内存碎片会对后续的内存分配造成问题。很可能需要分配一个大对象时,所有的碎片空间都无法完成,就会提前触发垃圾回收,而这次全量回收是不必要的。
5.3Mark-Compact老生代标记整理
在标记清除的基础上发展而来,在整理的过程中
1、 将活着的对象往一段移动
2、 移动完成后,直接清理掉边界外的内存
5.4Incremental Marking增量标记
垃圾回收的过程都需要将应用逻辑暂停下来。为了降低全量回收带来的停顿时间,在标记阶段,将原本一口气要完成的动作改为增量标记。垃圾回收与应用逻辑交替执行到标记阶段完成。最大停顿时间较少的1/6左右.
后续还引入了延迟清理与增量整理,让清理和整理动作也变成增量式的。
六、Javascript的V8引擎为什么快
针对上下文的Snapshot技术
什么是上下文(Contexts)?实际是JS应用程序的运行环境,避免应用程序的修改相互影响,例如一个页面js修改内置对象方法toString,不应该影响到另外页面。chrome浏览器每个process只有一个V8引擎实例,浏览器中的每个窗口、iframe都对应一个上下文。
Built-in的js代码
利用JS自表达内置对象、方法,如上面代码实现Math.min方法,从而V8在实现代码转译时只需注重基本操作,以%符号开头的函数来自V8运行时函数。
建立AST(Abstract SyntaxTree)时内存的管理。
V8在建立AST后,对其进行汇编生成动态机器语言,所以AST在code generated后需要回收;针对AST建立过程中多结点内存申请和一次性回收的特点,V8使用了内存段链表管理,并结合scopelock模式,实现少数申请(Segment,8KB~1MB)、多次分配AST结点、一次回收各个Segment的管理方式,既能避免内存碎片,又可以避免遍历AST结点逐个回收内存
CompileCache避免相同代码重复编译
对于一段JS代码,在开始进行词法分析前,会从编译缓存区CompilationCache查找该段代码是否已经被编译过,如果是,则直接取出编译过的机器代码,并返回,这样降低CPU的使用率,换来内存空间一定的占用;如果一个页面中重复加载JS文件,这方法的提速是很明显的;这种做法应该有平衡对比过。
属性的快速访问
V8没有像其它JS Engine使用词典结构或红黑树实现的map来管理属性,而是在每个对象附加一个指针,指向hidden class(如果第一次创建该类型对象,则新建hidden class);当对象每添加一个属性时,将新建一个class(记录了每个属性的位移/位置),而原来的class指向新class,即建立起一个hidden class的转换链表。
Heap堆内存管理
Inline caching减少函数调用开销
函数绑定发生在运行时,所以无法通过method tables定位函数入口;通过该技术可以记录函数入口,避免重复查找。
一次性编译生成机器语言
一般JS engine会在AST生成后,将之编译为中间语言(bytecode),在执行时候再解析这些bytecode;Java 也同样编译为这些bytecode,再采用VM(实现跨平台)作为解释器,为了提高效能,Java采用混杂方式,把无关平台、常用的代码编译为机器代码。V8则是一次性把AST编译为机器语言。从assembler相关文件头的Copyright可以看出,这些不同平台(ia32, arm)下的编译器,原型来自Sun Microsystems。
参考:www.cxymsg.com/guide/mecha…
作者:蜗牛的北极星之旅
链接:https://juejin.im/post/5d86496be51d453bdb1d9c11
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- 点赞
- 收藏
- 关注作者
评论(0)