关于v8:D8调试工具jsvu的使用细则

d8 is V8’s own developer shell. D8 是一个十分有用的调试工具,你能够把它看成是 debug for V8 的缩写。咱们能够应用 d8 来查看 V8 在执行 JavaScript 过程中的各种两头数据,比方作用域、AST、字节码、优化的二进制代码、垃圾回收的状态,还能够应用 d8 提供的公有 API 查看一些外部信息。 前言jsvu 是 JavaScript 引擎版本管理工具 以下是在Windows10下的操作,倡议在 CMD 窗口外面操作。 1、装置前提:node V14+ npm install -g jsvu运行 jsvu,交互式命令行抉择须要装置的平台和引擎 装置指定版本的引擎能够参考上面的命令 jsvu --os=win64 --engines=v8,v8-debug 执行 jsvu装置引擎,可在 %USERPROFILE% /.jsvu 目录下查看装置的引擎 装置 v8-debug jsvu --os=win64 --engines=v8-debug 操作系统反对的引擎JavaScript engineBinary namemac64mac64armwin32win64linux32linux64Chakrachakra or ch✅❌✅✅❌✅GraalJSgraaljs✅❌❌✅❌✅Hermeshermes & hermes-repl✅❌❌✅❌✅JavaScriptCorejavascriptcore or jsc✅✅❌✅ *❌✅QuickJSquickjs❌❌✅✅✅✅SpiderMonkeyspidermonkey or sm✅✅✅✅✅✅V8v8✅✅✅✅✅✅V8 debugv8-debug✅✅✅✅✅✅XSxs✅ (32)❌✅✅ (32)✅✅查看jsvu版本jsvu -h jsvu v1.13.3 — the JavaScript engine Version Updater [<engine>@<version>][--os={mac64,mac64arm,linux32,linux64,win32,win64,default}][--engines={chakra,graaljs,hermes,javascriptcore,quickjs,spidermonkey,v8,v8-debug,xs},…]Complete documentation is online:https://github.com/GoogleChromeLabs/jsvu#readme2、装置 eshost-cli(这个不装置也不影响应用)治理js引擎,能够调用多个引擎执行js代码,更加不便调试不同引擎下的代码 ...

August 17, 2022 · 4 min · jiezi

关于v8:深入理解之V8引擎的垃圾回收机制

本文谨用于笔者集体了解和总结V8引擎的垃圾回收机制,本文次要参考一文搞懂V8引擎的垃圾回收 在理解V8垃圾回收机制之前,咱们先来论述一些概念: 「全进展」:垃圾回收算法在执行前,须要将应用逻辑暂停,执行完垃圾回收后再执行应用逻辑。如果一次GC须要50ms,应用逻辑就会暂停50ms。为什么会暂停呢? ①因为js是单线程执行的,进入垃圾回收后,js应用逻辑须要暂停,以留出空间给垃圾回收算法运行。②垃圾回收其实是十分耗时间的操作。 V8引擎垃圾回收策略:V8的垃圾回收策略次要是基于分代式垃圾回收机制,其依据对象的存活工夫将内存的垃圾回收进行不同的分代,而后对不同的分代采纳不同的垃圾回收算法。在新生代的垃圾回收过程中次要采纳了Scavenge算法;在老生代采纳Mark-Sweep(标记革除)和Mark-Compact(标记整顿)算法。在理解新生代和老生代的垃圾治理算法之前,咱们无妨先来理解一下V8引擎垃圾治理的内存构造; V8引擎垃圾治理的内存构造:新生代(new_space):大多数的对象开始都会被调配在这里,这个区域绝对较小然而垃圾回收特地频繁,该区域被分为两半,一半用来分配内存,另一半用于在垃圾回收时将须要保留的对象复制过去。(笔者看到了两种分区说法:①From区:To区=1:1②From区:To区:To区=8:1:1,本文仅用来理解回收机制,不对此处过多探讨)老生代(old_space):新生代中的对象在存活一段时间后就会被转移到老生代内存区,绝对于新生代该内存区域的垃圾回收频率较低。老生代又分为老生代指针区和老生代数据区,前者蕴含大多数可能存在指向其余对象的指针的对象,后者只保留原始数据对象,这些对象没有指向其余对象的指针。大对象区(large_object_space):寄存体积超过其余区域大小的对象,每个对象都会有本人的内存,垃圾回收不会挪动大对象区。代码区(code_space):代码对象,会被调配在这里,惟一领有执行权限的内存区域。map区(map_space):寄存Cell和Map,每个区域都是寄存雷同大小的元素,构造简略。新生代区:新生代区次要采纳Scavenge算法实现,它将新生代区划分为激活区(new space)又称为From区和未激活区(inactive new space)又称为To区。程序中生命的对象会被存储在From空间中,当新生代进行垃圾回收时,处于From区中的尚存的沉闷对象会复制到To区进行保留,而后对From中的对象进行回收,并将From空间和To空间角色对换,即To空间会变为新的From空间,原来的From空间则变为To空间。因而,该算法是一个就义空间来换取工夫的算法。 基于上述算法,算法图解实现如下(转载): 假如咱们在From空间中调配了三个对象A、B、C当程序主线程工作第一次执行结束后进入垃圾回收时,发现对象A曾经没有其余援用,则示意能够对其进行回收对象B和对象C此时仍旧处于沉闷状态,因而会被复制到To空间中进行保留接下来将From空间中的所有非存活对象全副革除此时From空间中的内存曾经清空,开始和To空间实现一次角色调换当程序主线程在执行第二个工作时,在From空间中调配了一个新对象D工作执行结束后再次进入垃圾回收,发现对象D曾经没有其余援用,示意能够对其进行回收象B和对象C此时仍旧处于沉闷状态,再次被复制到To空间中进行保留再次将From空间中的所有非存活对象全副革除From空间和To空间持续实现一次角色调换对象降职:当一个对象在通过屡次复制之后仍旧存活,那么它会被认为是一个生命周期较长的对象,在下一次进行垃圾回收时,该对象会被间接转移到老生代中,这种对象从新生代转移到老生代的过程咱们称之为降职。对象降职的条件次要有以下两个(满足其一即可): 对象是否经验过一次Scavenge算法To空间的内存占比是否曾经超过25%默认状况下,咱们创立的对象都会调配在From空间中,当进行垃圾回收时,在将对象从From空间复制到To空间之前,会先查看该对象的内存地址来判断是否曾经经验过一次Scavenge算法,如果地址曾经产生变动则会将该对象转移到老生代中,不会再被复制到To空间。流程图示意: 如果对象没有经验过Scavenge算法,会被复制到To空间,然而如果此时To空间的内存占比曾经超过25%,则该对象依旧会被转移到老生代,如下图所示: 之所以有25%的内存限度是因为To空间在经验过一次Scavenge算法后会和From空间实现角色调换,会变为From空间,后续的内存调配都是在From空间中进行的,如果内存应用过高甚至溢出,则会影响后续对象的调配,因而超过这个限度之后对象会被间接转移到老生代来进行治理。 老生代区:在解说老生代Mark-Sweep(标记革除)和Mark-Compact(标记整顿)算法之前,先来回顾一下援用计数法:对于对象A,任何一个对象援用了A的值,计数器+1,援用生效时计数器-1,当计数器为0时指责回收,然而会存在循环援用的状况,可能会导致内存透露,自2012年起,所有的古代浏览器均放弃了这种算法。 function foo() {//循环援用样例 let a = {}; let b = {}; a.a1 = b; b.b1 = a;}foo();Mark-Sweep(标记革除)算法:Mark-Sweep(标记革除)分为标记和革除两个阶段,在标记阶段会遍历堆中的所有对象,而后标记活着的对象,在革除阶段中,会将死亡的对象进行革除。Mark-Sweep算法次要是通过判断某个对象是否能够被拜访到,从而晓得该对象是否应该被回收,具体步骤如下: 垃圾回收器会在外部构建一个根列表,用于从根节点登程去寻找那些能够被拜访到的变量。比方在JavaScript中,window全局对象能够看成一个根节点。垃圾回收器从所有根节点登程,遍历其能够拜访到的子节点,并将其标记为流动的,根节点不能到达的中央即为非流动的,将会被视为垃圾。垃圾回收器将会开释所有非流动的内存块,并将其归还给操作系统。然而通过标记革除之后的内存空间会⽣产很多不间断的碎⽚空间,这种不间断的碎⽚空间中,在遇到较⼤的对象时可能会因为空间不⾜⽽导致⽆法存储。为了解决内存碎⽚的问题,须要使⽤另外⼀种算法:标记-整顿(Mark-Compact)。标记-整顿(Mark-Compact):标记整顿看待未存活对象不是⽴即回收,⽽是将存活对象挪动到⼀边,而后间接清掉端边界以外的内存。这里为了便于了解,援用两个流程图。 假如在老生代中有A、B、C、D四个对象在垃圾回收的标记阶段,将对象A和对象C标记为流动的在垃圾回收的整顿阶段,将流动的对象往堆内存的一端挪动在垃圾回收的革除阶段,将流动对象左侧的内存全副回收至此就实现了一次老生代垃圾回收的全副过程,然而因为前文提到的「全进展」的存在,在标记阶段同样会妨碍主线程的执行,一般来说,老生代会保留大量存活的对象,如果在标记阶段将整个堆内存遍历一遍,那么势必会造成重大的卡顿。因而,V8引擎有引入了Incremental Marking(增量标记)的概念。Incremental Marking(增量标记): 将本来须要一次性遍历堆内存的操作改为增量标记的形式,先标记堆内存中的一部分对象,而后暂停,将执行权从新交给JS主线程,待主线程工作执行结束后再从原来暂停标记的中央持续标记,直到标记残缺个堆内存。即:把垃圾回收这个⼤的工作分成⼀个个⼩工作,穿插在 JavaScript工作两头执⾏这个理念其实有点像React框架中的Fiber架构,只有在浏览器的闲暇工夫才会去遍历Fiber Tree执行对应的工作,否则提早执行,尽可能少地影响主线程的工作,防止利用卡顿,晋升利用性能。得益于增量标记的益处,V8引擎后续持续引入了提早清理(lazy sweeping)和增量式整顿(incremental compaction),让清理和整顿的过程也变成增量式的。同时为了充分利用多核CPU的性能,也将引入并行标记和并行清理,进一步地缩小垃圾回收对主线程的影响,为利用晋升更多的性能。最初附上V8-GC的触发机制:参考文献及图片出处: 一文搞懂V8引擎的垃圾回收Node —— V8 GC 浅析浅谈V8引擎垃圾回收机制

July 2, 2022 · 1 min · jiezi

关于v8:V8是怎么执行JS代码的

1、V8的演进历史 2008年V8公布第一个版本,过后的V8架构比拟激进,间接将js代码编译为机器码并执行,所以执行速度很快,然而只有Codegen一个编译器,所以对代码的优化很无限。 2010年V8公布了Crankshaft编译器,js代码会先被Full-Codegen编译器编译,如果后续改代码块会被屡次执行,则会用Crankshaft编译器从新编译,生成更优化的代码,之后就应用优化后的代码来执行,进而晋升性能。 Crankshaft编译器对代码的优化无限,所以2015年V8中退出了TurboFan编译器,此时V8仍旧是间接将源码编译为机器码执行,这种架构存在一个外围问题,内存耗费特地大(通常一个几KB的文件,转换为机器码可能就是几十MB,这会小号微小的内存空间)。 2016年V8退出了Ignition编译器,从新引入字节码,旨在缩小内存应用。 2017年V8正式公布全新编译pipeline,它应用Ignition和TurboFan的组合来编译执行代码,从这(V8的5.9版本)开始,晚期的Full-Codegen和Crankshaft编译器不再用来执行js,在最新的架构中,最外围的模块有三个:解析器(Parser)、解释器(Ignition)、优化编译器(TurboFan)。 当V8执行js源码时,首先,解析器会把源码解析为形象语法树(Abstract Syntax Tree),解释器再将AST翻译为字节码,一边解释一边执行,在此过程中,解释器会记录特定代码片段的运行次数,如果运行次数超过了某个阈值,该段代码就被标记为热代码(hot code),并将运行信息反馈给优化编译器(TureboFan),优化编译器依据反馈信息,优化并编译字节码,最终生成优化后的机器码,这样,当该段代码再次被执行时,解释器就间接应用优化后的机器码执行,不必再次解释,从而大大提高了代码运行效率,这种在运行时编译代码的技术叫即时编译(JIT)。 2、V8的解析器将js源码解析为AST,此过程会通过词法剖析、语法分析,通过预解析进步执行效率。 词法剖析:将js源码解析为一个个最小单元的token。 在V8中,Scanner负责接管Unicode字符流,并将其解析为tokens提供给解析器应用。 语法分析:依据语法规定,将tokens组成一个具备前台层级的形象语法树,在这个过程中,如果源码不合乎语法标准,解析过程就会终止,并抛出语法错误。 对于一份js源码,如果所有源码都要通过解析能力执行,那必然会面临三个问题:1、一次性解析所有代码,代码执行工夫变长,2、内存耗费减少,因为解析完的AST以及依据AST编译后的字节码都会寄存在内存中,3、占用磁盘空间,编译后的代码会缓存在磁盘上。 因而,当初支流的浏览器都会进行提早解析,在解析过程中,对于不是立刻执行的函数,只进行预解析(Pre Parser),只有当函数调用时才对函数进行全量解析。进行预解析时,只验证函数的语法是否无效,解析函数申明,确定函数作用域,不生成AST。实现预解析的就是Pre-Parser解析器。 3、V8的解释器Js源码转换为CPU可辨认的机器码,须要耗费微小的内存,V8为了解决内存内存占用问题引入了字节码。字节码是对机器码的形象,语法与汇编有些相似,能够把它看做一个一个的指令。 解析器Ignition依据AST生成字节码并执行。 这个过程中会收集反馈信息,交给TurboFan进行优化编译。TurboFan依据Ignition收集的反馈信息,将字节码编译为优化后的机器码,后续Ignition有优化后的机器码代替字节码执行。 4、V8的优化编译器Ignition解释器在执行字节码时,仍旧须要将字节码转换为机器码,因为CPU只能辨认机器码,尽管多了一层字节码的转换,看起来效率低了,然而相比于机器码,基于字节码能够更不便的进行性能优化,其中最次要的优化就是应用TurboFan编译器编译热点代码。Ignitio解释器在解释执行的过程中,会标记反复执行的热点代码,这些被标记的代码,会被TurboFan编译器编译生成效率更高的机器码。 TurboFan在工作的时候次要用到了两个算法,一个内联,一个是逃逸剖析。 内联就是对嵌套函数进行内联剖析,如下图左侧代码,如果不经优化,间接编译该段代码,则会生成两个函数的机器码,但为了进一步晋升性能,TurboFan就会对这两个函数进行内联,而后在编译,如下提中间代码,更进一步,因为函数外部变量的值都是确定的,所以函数还能够进一步优化,如下图右侧代码。最终生成的机器码相比优化前少了十分多,执行效率天然也就高了。通过内联,能够升高复杂度,打消冗余代码,合并常量,并且,内联技术通常也是逃逸剖析的根底。 逃逸剖析是剖析对象的生命周期是否仅限于以后函数,如果对象是在函数外部定义的,且对象只作用于函数外部,比方对象没有被返回,也没有传递或者给其余函数调用,此时,这个对象会被认为是”未逃逸”的。在编译优化时,会应用标量替换掉未逃逸的对象,以缩小对象定义,从而缩小从内存中拜访对象属性,晋升了执行效率的同时,还缩小了内存的应用。 文章来源于视频:https://www.zhihu.com/zvideo/...

April 1, 2022 · 1 min · jiezi

关于v8:浏览器工作原理和V8引擎

一、浏览器的工作原理 比方在浏览器中输出网址,而后dns进行解析,解析出的就是服务器的一个ip地址。服务器返回一个html文件,浏览器内核在解析html文件的过程中,遇到link标签和script标签援用的css文件和JavaScript文件就会去下载下来。 二、浏览器内核 咱们常常会说:不同的浏览器有不同的内核组成:Gecko:晚期被Netscape和Mozilla Firefox浏览器浏览器应用;Trident:微软开发,被IE4~IE11浏览器应用,然而Edge浏览器曾经转向Blink;Webkit:苹果基于KHTML开发、开源的,用于Safari,Google Chrome之前也在应用;Blink:是Webkit的一个分支,Google开发,目前利用于Google Chrome、Edge、Opera等;等等... 事实上,咱们常常说的浏览器内核指的是浏览器的排版引擎:排版引擎(layout engine),也称为浏览器引擎(browser engine)、页面渲染引擎(rendering engine) 或样版引擎。三、浏览器渲染过程 浏览器内核的 HTML Parse 将 HTML 转化为DOM树(DOM Tree),DOM 的 JavaScript 代码能够对DOM树(DOM Tree)进行操作(JavaScript代码是由JavaScript引擎执行的)。CSS Parse 将css转化为CSS规定(Style Rules)。而后 DOM树(DOM Tree)和CSS规定(Style Rules)通过附加(Attachment)生成渲染树(Render Tree),在 布局引擎(Layout)具体操作下,进行绘制(Painting),浏览器就能够进行展现(Dispaly)。之所以须要布局引擎(Layout),是因为浏览器在不同状态下布局有所不同。 四、意识JavaScript引擎 为什么须要JavaScript引擎呢?咱们后面说过,高级的编程语言都是须要转成最终的机器指令来执行的;事实上咱们编写的JavaScript无论你交给浏览器或者Node执行,最初都是须要被CPU执行的;然而CPU只意识本人的指令集,实际上是机器语言,能力被CPU所执行;所以咱们须要JavaScript引擎帮忙咱们将JavaScript代码翻译成CPU指令来执行; 比拟常见的JavaScript引擎有哪些呢?SpiderMonkey:第一款JavaScript引擎,由Brendan Eich开发(也就是JavaScript作者);Chakra:微软开发,用于IT浏览器;JavaScriptCore:WebKit中的JavaScript引擎,Apple公司开发;V8:Google开发的弱小JavaScript引擎,也帮忙Chrome从泛滥浏览器中怀才不遇;等等… JavaScript是一门高级编程语言:机械语言————>汇编语言————>高级语言五、浏览器内核和JS引擎的关系这里咱们先以WebKit为例,WebKit事实上由两局部组成的: WebCore:负责HTML解析、布局、渲染等等相干的工作;JavaScriptCore:解析、执行JavaScript代码;另外一个弱小的JavaScript引擎就是V8引擎。 六、V8引擎原理 咱们来看一下官网对V8引擎的定义:V8是用C ++编写的Google开源高性能JavaScript和WebAssembly引擎,它用于Chrome和Node.js等。它实现ECMAScript和WebAssembly,并在Windows 7或更高版本,macOS 10.12+和应用x64,IA-32, ARM或MIPS处理器的Linux零碎上运行。V8能够独立运行,也能够嵌入到任何C ++应用程序中。 V8引擎架构Parse模块会将JavaScript代码转换成AST(形象语法树),这是因为解释器并不间接意识JavaScript代码如果函数没有被调用,那么是不会被转换成AST的。PreParse(预解析),并不是一开始所有代码都须要执行,所以V8引擎就实现了Lazy Parsing(提早解析)的计划,它的作用是将不必要的函数进行预解析,也就是只解析暂 时须要的内容,而对函数的全量解析是在函数被调用时才会进行; Ignition是一个解释器,会将AST转换成ByteCode(字节码)同时会收集TurboFan优化所须要的信息(比方函数参数的类型信息,有了类型能力进行实在的运算); 如果函数只调用一次,Ignition会执行解释执行ByteCode; TurboFan是一个编译器,能够将字节码编译为CPU能够间接执行的机器码如果一个函数被屡次调用,那么就会被标记为热点函数,那么就会通过TurboFan转换成优化的机器码,进步代码的执行性能; 然而,机器码实际上也会被还原为ByteCode,这是因为如果后续执行函数的过程中,类型产生了变动(比方sum函数原来执行的是 number类型,起初执行变成了string类型),之前优化的机器码并不能正确的解决运算,就会逆向的转换成字节码。 七、执行上下文 <script> var name = 'why' foo(123) function foo (num) { console.log(m) var m = 10 var n = 20 function bar () { console.log(name) } bar() }</script>复制代码全局代码执行前的解析(红色框内) ...

March 11, 2022 · 1 min · jiezi

关于v8:v8

v8常识图谱v8常识图谱 v8的根底环境v8执行流程事件循环系统javascript的设计思维垃圾回收零碎v8的根底环境v8的根底环境 堆空间 树状存储构造存储对象存储闭包函数援用的原生类型栈空间 先进后出存储原生类型全局执行上下文 初始化的this全局作用域全局对象宿主环境 宿主类型浏览器NodeJs其它宿主 内置内置函数内置对象 Chrome.windowNode.global事件循环系统 音讯列表任务调度零碎javascript的设计思维javascript的设计思维 函数是一等公民 函数领有一般类型的个性基于对象设计对象是动静的反对闭包函数表达式类型零碎和垃圾回收 类型零碎垃圾回收作用域 源代码中定义变量的区域动态作用域动静作用域javascript是基于动态作用域的作用域链原型链继承 原型原型链new关键字事件循环系统什么是事件循环系统 JavaScript是单线程模式单线程同时只执行一个工作有新的工作就须要排队执行引入音讯队列音讯队列中的工作就是宏工作任务调度器循环读取音讯队列中的工作分派给指定的工作处理器异步编程 回调函数模式Promise模式await/async模式

February 15, 2022 · 1 min · jiezi

关于v8:教女朋友学前端之深入理解JS引擎

美味值: 口味:番茄肥牛 食堂老板娘:老板,Chrome V8 引擎工作原理面试会问吗? 食堂老板:这块的常识不仅面试可能会问,学会了 JS 引擎的工作原理,能够更好的了解 JavaScript、更好的了解前端生态中 Babel 的词法剖析和语法分析,ESLint 的语法查看原理以及 React、Vue 等前端框架的实现原理。总之,学习引擎原理堪称是一举多得。 食堂老板娘:好好好,别罗嗦了,快开始吧~ 宏观视角看 V8V8 是咱们前端届的网红,它用 C++ 编写,是谷歌开源的高性能 JavaScript 和 WebAssembly 引擎,次要用在 Chrome、Node.js、Electron...中。 在开始讲咱们的配角 V8 引擎之前,先来从宏观视角开展谈谈 V8 所处的地位,建设一个世界观。 在信息科技高速倒退的明天,这个疯狂的大世界充斥着各种电子设备,咱们每天都用的手机、电脑、电子手表、智能音箱以及当初马路上跑的越来越多的电动汽车。 作为软件工程师,咱们能够将它们对立了解为“电脑”,它们都是由中央处理器(CPU)、存储以及输出、输出设备形成。CPU 就像厨师,负责依照菜谱执行命令烧菜。存储如同冰箱,负责保留数据以及要执行的命令(食材)。 当电脑接通电源,CPU 便开始从存储的某个地位读取指令,依照指令一条一条的执行命令,开始工作。电脑还能够接入各种外部设备,比方:鼠标、键盘、屏幕、发动机等等。CPU 不须要全副搞清楚这些设施的能力,它只负责和这些设施的端口进行数据交换就好。设施厂商也会在提供设施时,附带与硬件匹配的软件,来配合 CPU 一起工作。说到这里,咱们便失去了最根底的计算机,也是计算机之父冯·诺伊曼在 1945 年提出的体系结构。 不过因为机器指令人类读起来十分不敌对,难以浏览和记忆,所以人们创造了编程语言和编译器。编译器能够把人类更容易了解的语言转换为机器指令。除此之外,咱们还须要操作系统,来帮咱们解决软件治理的问题。咱们晓得操作系统有很多,如 Windows、Mac、Linux、Android、iOS、鸿蒙等,应用这些操作系统的设施更是不可胜数。为了打消客户端的多样性,实现跨平台并提供对立的编程接口,浏览器便诞生了。 所以,咱们能够将浏览器看作操作系统之上的操作系统,而对于咱们前端工程师最相熟的 JavaScript 代码来说,浏览器引擎(如:V8)就是它的整个世界。 星球最强 JavaScript 引擎毫无疑问,V8 是最风行、最强的 JavaScript 引擎,V8 这个名字的灵感来源于 50 年代经典的“肌肉车”的引擎。 Programming Languages Software AwardV8 也曾取得了学术界的必定,拿到了 ACM SIGPLAN 的 Programming Languages Software Award。 支流 JS 引擎JavaScript 的支流引擎如下所示: ...

August 16, 2021 · 3 min · jiezi

关于v8:走进chrome内心了解V8引擎是如何工作的

作为一个前端程序员,每天下班的第一件事就是关上电脑,情不自禁的点开chrome浏览器,或是摸会儿鱼或是立马进入工作状态。接下来浏览器窗口就会陪伴着你度过一天的时光,失常到七八点钟,晚点就九十点钟,再晚点就陪你跨过一天,时刻关注着你的工作。作为一个虔诚陪伴你的搭档,你扪心自问,你有认真的理解过它是如何工作的吗?你有走进过它的内心世界吗? 如果你也好奇过,那么请收看这期的《走进chrome心田,理解V8引擎是如何工作的》。 V8是什么在深刻理解一件事物之前,首先要晓得它是什么。 V8是一个由Google开源的采纳C++编写的高性能JavaScript和WebAssembly引擎,利用在 Chrome和Node.js等中。它实现了ECMAScript和WebAssembly,运行在Windows 7及以上、macOS 10.12+以及应用x64、IA-32、ARM或MIPS处理器的Linux零碎上。 V8能够独立运行,也能够嵌入到任何C++应用程序中。 V8由来接下来咱们来关怀关怀它如何诞生的,以及为什么叫这个名字。 V8最后是由Lars Bak团队开发的,以汽车的V8发动机(有八个气缸的V型发动机)进行命名,预示着这将是一款性能极高的JavaScript引擎,在2008年9月2号同chrome一起开源公布。 为什么须要V8咱们写的JavaScript代码最终是要在机器中被执行的,但机器无奈间接辨认这些高级语言。须要通过一系列的解决,将高级语言转换成机器能够辨认的的指令,也就是二进制码,交给机器执行。这两头的转换过程就是V8的具体工作。 接下来咱们就来具体的理解一下。 V8组成首先来看一下V8的外部组成。V8的外部有很多模块,其中最重要的4个如下: Parser: 解析器,负责将源代码解析成ASTIgnition: 解释器,负责将AST转换成字节码并执行,同时会标记热点代码TurboFan: 编译器,负责将热点代码编译成机器码并执行Orinoco: 垃圾回收器,负责进行内存空间回收V8工作流程以下是V8中几个重要模块的具体工作流程图。咱们一一剖析。 Parser解析器Parser解析器负责将源代码转换成形象语法树AST。在转换过程中有两个重要的阶段:词法剖析(Lexical Analysis)和语法分析(Syntax Analysis)。 词法剖析也称为分词,是将字符串模式的代码转换为标记(token)序列的过程。这里的token是一个字符串,是形成源代码的最小单位,相似于英语中单词。词法剖析也能够了解成将英文字母组合成单词的过程。词法剖析过程中不会关怀单词之间的关系。比方:词法剖析过程中可能将括号标记成token,但并不会校验括号是否匹配。 JavaScript中的token次要蕴含以下几种: 关键字:var、let、const等 标识符:没有被引号括起来的间断字符,可能是一个变量,也可能是 if、else 这些关键字,又或者是 true、false 这些内置常量 运算符: +、-、 *、/ 等 数字:像十六进制,十进制,八进制以及迷信表达式等 字符串:变量的值等 空格:间断的空格,换行,缩进等 正文:行正文或块正文都是一个不可拆分的最小语法单元 标点:大括号、小括号、分号、冒号等 以下是const a = 'hello world'通过esprima词法剖析后生成的tokens。 [ { "type": "Keyword", "value": "const" }, { "type": "Identifier", "value": "a" }, { "type": "Punctuator", "value": "=" }, { "type": "String", "value": "'hello world'" }]语法分析语法分心是将词法剖析产生的token依照某种给定的模式文法转换成AST的过程。也就是把单词组合成句子的过程。在转换过程中会验证语法,语法如果有错的话,会抛出语法错误。 ...

July 12, 2021 · 1 min · jiezi

关于v8:v8-Heapsnapshot-文件解析

图片起源:debugging-memory-leaks-node-js-applications本文作者:肖思元在 node 中能够通过 v8.getHeapSnapshot 来获取利用以后的堆快照信息,该调用会生成一份 .heapsnapshot 文件,官网并没有对该文件的内容有一个具体的解释,本文将次要对该文件内容进行解析,并演示了一个理解文件内容后能够做的乏味的事件 v8.getHeapSnapshot首先简略回顾下 v8.getHeapSnapshot 是如何应用的: // test.jsconst { writeHeapSnapshot } = require("v8");class HugeObj { constructor() { this.hugeData = Buffer.alloc((1 << 20) * 50, 0); }}// 留神上面的用法在理论利用中通常是 anti-pattern,// 这里只是为了不便演示,才将对象挂到 module 上以避免被 GC 开释module.exports.data = new HugeObj();writeHeapSnapshot();将下面的代码保留到 test.js 中,而后运行 node test.js,会生成文件名相似 Heap.20210228.154141.9320.0.001.heapsnapshot 的文件,该文件能够应用 Chrome Dev Tools 进行查看 对于下面的步骤咱们也能够间接 查看视频演示当咱们将 .heapsnapshot 文件导入到 Chrome Dev Tools 之后,咱们会看到相似上面的内容:上图表格列出了以后堆中的所有对象,其中列的含意是:Constructor,示意对象是应用该函数结构而来Constructor 对应的实例的数量,在 Constructor 前面的 x2 中显示Shallow size,对象本身大小(单位是 Byte),比方下面的 HugeObj,它的实例的 Shallow size 就是本身占用的内存大小,比方,对象外部为了保护属性和值的对应关系所占用的内存,并不蕴含持有对象的大小比方 hugeData 属性援用的 Buffer 对象的大小,并不会计算在 HugeObj 实例的 Shallow size 中Retained size,对象本身大小加上它依赖链路上的所有对象的本身大小(Shallow size)之和Distance,示意从根节点(Roots)达到该对象通过的最短门路的长度heapsnapshot 文件Chrome Dev Tools 只是 .heapsnapshot 文件的一种展示模式,如果咱们心愿最大水平利用这些信息,则须要进一步理解其文件格式咱们能够应用任意的文本编辑器关上该文件,能够发现文件内容其实是 JSON 格局的:因为目前没有具体的阐明文档,前面的内容咱们将联合源码来剖析该文件的内容 ...

March 17, 2021 · 4 min · jiezi