这节讲解的是JavaScript的内存机制。 首先,我们知道JavaScript是弱类型动态语言。 接着,JavaScript的数据类型一共是八种:Boolean| String | Number | Undefined | Null | BigInt | Symbol | Object 前七种为基本数据类型,他们存在栈中,后一种为引用数据类型,它存在堆中。
当一个函数执行完毕,JavaScript引擎会通过向下移动ESP(记录当前执行状态的指针)来销毁该函数保存在栈中的执行上下文。
要回收堆中的垃圾数据,就需要用到JavaScript中的垃圾回收器了。
代际假说(The Generaltional Hypothesis),是垃圾回收领域一个重要的术语,后续垃圾回收策略都是建立在该假说的基础上的。 特点一:大部分对象在内存中的时间很短,简单来说,很多对象一经分配内存,很快就变得不可访问。 特点二:不死的对象,会活的更久。
V8中会把堆分为新生代和老生代两个区域。新生代存放的是生存时间短的对象,老生代存放的是生存时间久的对象。 堆中的这两块区域,V8分别使用两个不同的垃圾回收器,以便高效的实施垃圾回收。 副垃圾回收器,主要负责新生代区域的垃圾回收。 主垃圾回收器,主要负责老生代区域的垃圾回收。
当执行垃圾回收算法的时候,JS脚本会暂停下来,这种行文叫做全停顿。 为了降低全停顿的卡顿影响,V8通过增量标记算法将完整的垃圾回收任务分为一个个小任务,并与JS脚本交替执行。
了解V8是如何执行一段JavaScript代码,可以让我们对babel、EsLint、Vue、React等其底层实现机制有一个更充分的认识。 首先,我们需要搞懂一些概念和原理:编译器(Compiler)、解释器(Interpreter)、抽象语法树(AST)、字节码(Bytecode)、**即时编译器(JIT)**等。
首先我们必须得知道编译型语言和解释型语言的区别。 编译型语言就是程序执行前,编辑器经过编译,成二进制文件,程序可直接运行二进制文件。如C/C++、Go 解释器语言是在运行时动态解释和执行。如JS、Python等。
编译型语言的编译过程:
V8执行过程中,既有解释器又有编译器。其执行流程为:
将源代码转换成抽象语法树,并生成执行上下文。 过程就是这么个过程,但是抽象语法树的理解我们要展开。
解释器登场,根据AST生成字节码、解释字节码。 一开始V8没有字节码,之前是直接生成机器码,这样的效率很高,但是很占内存,随着移动互联网的发展,为了解决内存占用过高问题,而引入了字节码,即字节码的内存占用要比机器码小很多。 字节码是介于AST和机器码之间的一种代码,它需要通过解释器将其转换为机器码后才能执行。
解释器除了生成字节码,还要解释字节码,后台编译器会把热点字节码编译成高效的机器码,这种字节码配合解释器和编译器的技术,就叫做即时编译(JIT).使用这种技术的除了V8还有Java和Python虚拟机等都使用了。