12 | 栈空间和堆空间:数据是如何存储的?

这节讲解的是JavaScript的内存机制
首先,我们知道JavaScript是弱类型动态语言。
接着,JavaScript的数据类型一共是八种:Boolean| String | Number | Undefined | Null | BigInt | Symbol | Object
前七种为基本数据类型,他们存在栈中,后一种为引用数据类型,它存在堆中。

13 | 垃圾回收:垃圾数据是如何自动回收的?

不同语言的垃圾回收策略

  • 通常情况下,垃圾回收分为手动回收和自动回收两种策略。
  • 手动垃圾回收:例如C++,何时分配内存、何时销毁是由代码控制的。
  • 自动垃圾回收:JavaScript、Java、Python等,产生的垃圾数据是由垃圾回收器释放的。

调用栈中的数据是如何回收的

当一个函数执行完毕,JavaScript引擎会通过向下移动ESP(记录当前执行状态的指针)来销毁该函数保存在中的执行上下文。

堆中的数据是如何回收的

要回收堆中的垃圾数据,就需要用到JavaScript中的垃圾回收器了。

代际假说

代际假说(The Generaltional Hypothesis),是垃圾回收领域一个重要的术语,后续垃圾回收策略都是建立在该假说的基础上的。
特点一:大部分对象在内存中的时间很短,简单来说,很多对象一经分配内存,很快就变得不可访问。
特点二:不死的对象,会活的更久。

堆中区域

V8中会把堆分为新生代老生代两个区域。新生代存放的是生存时间短的对象,老生代存放的是生存时间久的对象。
堆中的这两块区域,V8分别使用两个不同的垃圾回收器,以便高效的实施垃圾回收。
副垃圾回收器,主要负责新生代区域的垃圾回收。
主垃圾回收器,主要负责老生代区域的垃圾回收。

垃圾回收器工作流程

  1. 标记空间中的活动对象和不活动对象。
  2. 回收非活动对象所占据的内存。
  3. 内存整理(主垃圾回收器产生的内存碎片会导致出现不连续内存空间,所以需要整理)

副垃圾回收器

  1. 负责新生代区域的垃圾回收
  2. 大多数小的对象会分配至此。
  3. 新生代用Scavenge算法处理–》一半对象区域,一半空闲区域。
  4. 存活的对象放入对象区域,然后垃圾清理阶段,将对象区域中活跃对象复制至空闲区域,完成复制后,两个区域进行角色转换。
  5. 经过两次垃圾回收依然还存活的对象,会被移到老生区中。

主垃圾回收器

  1. 负责老生代区域的垃圾回收。
  2. 除了新生区中移过来的对象,一些大对象会被直接分配到老生区
  3. 老生区对象的特点:存活时间长,占用内存空间大。
  4. 主垃圾回收器采用的是标记-清除的算法进行垃圾回收。

全停顿

当执行垃圾回收算法的时候,JS脚本会暂停下来,这种行文叫做全停顿。
为了降低全停顿的卡顿影响,V8通过增量标记算法将完整的垃圾回收任务分为一个个小任务,并与JS脚本交替执行。

14 | 编译器和解释器:V8是如何执行一段JavaScript代码的?

了解V8是如何执行一段JavaScript代码,可以让我们对babel、EsLint、Vue、React等其底层实现机制有一个更充分的认识。
首先,我们需要搞懂一些概念和原理:编译器(Compiler)解释器(Interpreter)抽象语法树(AST)字节码(Bytecode)、**即时编译器(JIT)**等。

编译器和解释器

首先我们必须得知道编译型语言和解释型语言的区别。
编译型语言就是程序执行前,编辑器经过编译,成二进制文件,程序可直接运行二进制文件。如C/C++、Go
解释器语言是在运行时动态解释和执行。如JS、Python等。

编译器、解释器执行流程

编译型语言的编译过程:

  1. 编译器对源代码进行词法分析、语法分析,生成抽象语法树(AST)
  2. 优化代码,生成机器码、二进制文件。
  3. 编译成功,生成可执行文件。编译失败抛出异常。
    解释型语言解释过程:
  4. 解释器对源代码进行词法分析、语法分析,生成抽象语法树(AST)
  5. 基于抽象语法树生成字节码。
  6. 根据字节码执行程序、输出结果。

V8是如何执行一段JavaScript代码的

V8执行过程中,既有解释器又有编译器。其执行流程为:

1. 生成抽象语法树(AST)和执行上下文

将源代码转换成抽象语法树,并生成执行上下文。
过程就是这么个过程,但是抽象语法树的理解我们要展开。

  1. 无论编译型语言还是解释型语言,都会将源代码生成AST。
  2. AST的结构与代码结构类似。
    (Babel工作原理就是:ES6源码->ES6AST->ES5AST->ES5源码)
  3. 生成ATS经过两个阶段:
  • 第一阶段是分词(词法分析),将一行行源码拆解成不可再分的最小当个字符或字符串token。
  • 第二阶段是解析(语法分析),将token根据语法规则生成AST

2.生成字节码

解释器登场,根据AST生成字节码、解释字节码。
一开始V8没有字节码,之前是直接生成机器码,这样的效率很高,但是很占内存,随着移动互联网的发展,为了解决内存占用过高问题,而引入了字节码,即字节码的内存占用要比机器码小很多。
字节码是介于AST和机器码之间的一种代码,它需要通过解释器将其转换为机器码后才能执行。

3.执行代码

解释器除了生成字节码,还要解释字节码,后台编译器会把热点字节码编译成高效的机器码,这种字节码配合解释器和编译器的技术,就叫做即时编译(JIT).使用这种技术的除了V8还有Java和Python虚拟机等都使用了。