前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浏览器原理学习笔记03—V8工作原理

浏览器原理学习笔记03—V8工作原理

原创
作者头像
CS逍遥剑仙
修改2020-05-02 14:31:53
7870
修改2020-05-02 14:31:53
举报
文章被收录于专栏:禅林阆苑

浏览器原理学习笔记03—V8工作原理

Write By CS逍遥剑仙 我的主页: www.csxiaoyao.com GitHub: github.com/csxiaoyaojianxian Email: sunjianfeng@csxiaoyao.com

1. JavaScript 的数据类型

JavaScript 是弱类型(支持隐式类型转换),动态(运行时类型推断)语言。

JavaScript 的数据类型有 8 种:7 种 原始类型引用类型 (对象)

2. JavaScript 内存空间

2.1 内存模型

代码语言:txt
复制
function foo(){
    var a = "1"
    var b = a
    var c = {name:"1"}
    var d = c
}
foo()

栈空间通常不会设置太大,存放原始类型的小数据;堆空间很大,存放引用类型的数据,分配和回收内存会占用一定时间。

2.2 闭包对象产生过程

代码语言:txt
复制
function foo() {
    var myName = "1"
    let test1 = 1
    const test2 = 2
    var innerBar = { 
        setName:function(newName){
            myName = newName
        },
        getName:function(){
            console.log(test1)
            return myName
        }
    }
    return innerBar
}
var bar = foo()
bar.setName("test")
bar.getName()
  1. foo 函数执行并创建执行上下文;
  2. 预扫描 内部函数,编译过程中遇到内部函数如 setNamegetName 则对内部函数进行 快速词法扫描,发现引用了外部函数变量如 myNametest1 则判断为闭包,在堆空间创建 closure(foo) 对象(内部对象 JavaScript 无法访问)来存储闭包变量如 myNametest1
  3. 未被内部函数引用的变量如 test2 仍旧保存在调用栈中;
  4. 当 foo 函数退出,clourse(foo) 依然被其内部的 getNamesetName 方法引用。所以在下次调用 bar.setNamebar.getName 时,创建的执行上下文中就包含了 clourse(foo)

3. 自动垃圾回收

3.1 调用栈中的数据回收

JavaScript 引擎通过向下移动 ESP (记录当前执行状态的指针) 来销毁函数保存在栈中的执行上下文,效率很高。

代码语言:txt
复制
function foo(){
    var a = 1
    var b = {name:"test1"}
    function showName(){
      var c = "1"
      var d = {name:"test2"}
    }
    showName()
}
foo()

3.2 堆中的数据回收

3.2.1 代际假说和分代收集

代际假说: 大部分对象在内存中存在的时间很短 短期不死的对象,会活得更久

堆中的垃圾数据使用 JavaScript 中的垃圾回收器进行回收。V8 把堆分为 新生代老生代 两个区域,新生代中存放生存时间短的对象,老生代中存放生存时间久的对象。新生区通常只支持 1~8M 的容量,使用 副垃圾回收器 进行回收。老生区支持的容量较大,使用 主垃圾回收器 进行回收。

3.2.2 副垃圾回收器

新生代中用 Scavenge 算法 (空间对半划分为对象区域和空闲区域) 来处理。

新对象存放到对象区域,当对象区域快满时执行一次垃圾清理,先对对象区域中的垃圾做标记,再将存活的对象有序复制到空闲区域中,相当于完成了内存整理操作。完成复制后两个角色翻转,完成了垃圾清理。

因为复制时间不宜过长,一般新生区空间会设置得比较小,也因此很容易填满,JavaScript 引擎采用了 对象晋升策略 来解决,即经过两次垃圾回收依然存活的对象会被移动到老生区中。

3.2.3 主垃圾回收器

老生区中的对象占用空间大、存活时间长,一部分来自新生区中晋升的对象,一部分来自直接分配的大对象。

老生代采用 标记 - 清除 (Mark-Sweep) 算法进行垃圾回收。标记阶段从调用栈根元素开始递归遍历,根据能否到达区分 活动对象垃圾数据

垃圾清除阶段清除垃圾数据并产生大量不连续的内存碎片。再使用 标记 - 整理 (Mark-Compact) 算法在标记后将所有存活的对象移向一端,再直接清理边界以外的内存空间。

3.2.4 全停顿

由于 JavaScript 运行在渲染进程主线程上,执行垃圾回收将导致暂停执行 JavaScript 脚本,即 全停顿 (Stop-The-World)。为减少全停顿,V8 将标记过程分为多个的子标记过程,与 JavaScript 应用逻辑交替进行,直到标记阶段完成,称作 增量标记 (Incremental Marking) 算法。

4. 编译器和解释器

4.1 V8 执行 JavaScript 代码总览

编译器和解释器的区别。

JavaScript 是解释型语言,V8 执行 JavaScript 代码的流程总览。

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

4.2.1 AST 的应用
代码语言:txt
复制
var myName = "sunshine"
function foo(){
  return 18;
}
myName = "csxiaoyao"
foo()

经过 javascript-ast 处理后生成的 AST 结构如下:

AST 是非常重要的一种数据结构,编译器或解释器依赖于 AST,而非源代码。AST 在很多项目中有着广泛的应用,如:

  1. Babel 的工作原理是先将 ES6 源码转换为 AST,再将 ES6 语法的 AST 转换为 ES5 语法的 AST,最后利用 ES5 的 AST 生成 JavaScript 源代码
  2. ESLint 将源码转换为 AST,再利用 AST 来检查代码规范化的问题
4.2.2 AST 的生成

生成 AST 需要经历分词和解析两个阶段。

1. 分词 / 词法分析 (tokenize)

将源码拆解成一个个语法上不可再分、最小的单个字符或字符串 token

2. 解析 / 语法分析 (parse)

将 token 根据语法规则转为 AST

4.3 生成字节码

生成 AST 和执行上下文后,解释器 Ignition 会根据 AST 生成字节码,并解释执行字节码。

引入字节码是为了解决起初 V8 直接将 AST 转换为机器码而导致移动设备内存占用高的问题,字节码就是介于 AST 和机器码之间的一种代码,与特定类型的机器码无关,字节码需要通过解释器将其转换为机器码后才能执行。

4.4 执行代码 & JIT

第一次执行的字节码,解释器 Ignition 会逐条解释执行。在执行字节码的过程中,如果发现有热点代码(HotSpot),即一段代码被重复执行多次,后台编译器 TurboFan 会把该段热点字节码编译为高效的机器码,提高后续执行效率。字节码配合解释器和编译器的技术称为 即时编译 (JIT)。

4.5 JavaScript 性能优化策略

  1. 提升单次脚本的执行速度,避免 JavaScript 的长任务霸占主线程,使得页面快速响应交互;
  2. 避免大的内联脚本,因为在解析 HTML 的过程中,解析和编译也会占用主线程;
  3. 减少 JavaScript 文件的容量,提升下载速度,并且占用更低的内存。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 浏览器原理学习笔记03—V8工作原理
    • 1. JavaScript 的数据类型
      • 2. JavaScript 内存空间
        • 2.1 内存模型
        • 2.2 闭包对象产生过程
      • 3. 自动垃圾回收
        • 3.1 调用栈中的数据回收
        • 3.2 堆中的数据回收
      • 4. 编译器和解释器
        • 4.1 V8 执行 JavaScript 代码总览
        • 4.2 生成抽象语法树(AST)和执行上下文
        • 4.3 生成字节码
        • 4.4 执行代码 & JIT
        • 4.5 JavaScript 性能优化策略
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档