谷歌V8引擎运行机制概览

  • Post author:
  • Post category:其他


最近学习了极客时间上李兵大佬的谷歌V8引擎课程,总结了一下,在公司内部小组分享了一波,在此也分享一下,原理图直接用的专栏的图,由于时间有限,总结略显粗糙



注:

解释执行、编译执行各有优缺点:


解释执行,不需要做过多的编译,所以启动快,执行时不时直接运行机器码,顾运行慢;


编译执行,因为编译成机器语言或者更接近于机器语言,耗时更长,顾启动慢,但是喂给cpu的是机器码,所以执行快


注:

核心在于监控热点代码,发现多次调用的函数或变量,直接编译成机器码,放在内存中,供下次调用 ,提高了运行速度;不再被调用后,反编译会字节码,释放机器码存放内存,留给接下来的热点代码


注:

第一段代码,重复调用自己,函数只入栈,而不出栈,出栈的定义:把当前作用于内所有代码执行完毕后才出栈。这里函数a()内部包含log(3)和a(),必须两个函数都执行完毕才会将外层的a出栈,但是等不到出栈,又调用a函数,即又入栈了,所以外层的a永远无法出栈,导致爆栈,即栈溢出。


函数调用者的生命周期总是长于被调用者(后进),并且被调用者的生命周期总是先于调用者的生命周期结束 (先出)


所以站在函数资源分配和回收角度来看,被调用函数的资源分配总是晚于调用函数 (后进),而函数资源的释放则总是先于调用函数 (先出)


入栈是执行,是分配资源的过程,如内存、作用域等;出栈就是释放内存的过程


注:

因为内存资源宝贵,能分配到连续的内存资源是很难的,所以连续的栈资源比较小,适合存放较小的数据,比如原始数据类型;堆内存比较大,用于存放应用类数据,不要求连续,因为其地址指针放在栈中,就像坐标一样有经纬,不怕找不到。


注:


采用字节码作为中间代码是


不断优化尝试后的结果。


无法较为彻底优化:早期直接把代码转换为二进制机器码,缓存在内存中甚至硬盘中,以空间换时间,但内存占用巨大,且由于编译时只编译顶层代码,内部代码不会被编译,也就不会缓存,对于立即执行函数,无法缓存优化内部代码,移动端内存吃紧的情况下需继续优化


虽然采用字节码在执行速度上稍慢于机器代码,但是整体上权衡利弊,采用字节码也许是最优解。之所以说是最优解,是因为采用字节码除了降低内存之外,还提升了代码的启动速度,并降低了代码的复杂度,而牺牲的仅仅是一点执行效率


注:


字节码可根据不同平台转为对应的机器码,不用生成多套机器码,因为不同的 CPU 架构平台


ram不同,命令不同,需要不同的机器码


注:


宏任务如:console.log、setTimeout、var、let等;每个宏任务在执行时,V8 都会重新创建栈,然后随着宏任务中函数调用,栈也随之变化,最终,当该宏任务执行结束时,整个栈又会被清空,接着主线程继续执行下一个宏任务。JavaScript 中之所以要引入微任务,颗粒度更细,时效性上更好。怎么理解这句话呢,和以前通过浏览器api setTimeout实现异步编程对比就很直观了,setTimeout是宏任务,他的回调会放到消息队列尾部去排队等待执行,前面不管排了多少个任务都么法,急也没用,谁让你排在后面呢;而微任务的回调则被放在当前宏任务的最后,再怎么说也是和当前宏任务同步执行的,不会说被其它宏任务插队,所以说控制的粒度更细,更精确。但严格来说,不管是现在借助微任务还是以前用setTimeout来实现异步编程,都没法精确控制具体延迟时间的,只能说用微任务更接近于期望值。


注:

打印结果foo bar global mirco-foo micro-bar micro-global  macro-foo macro-bar macro-global



版权声明:本文为dongguan_123原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。