本文主要就下面三块内容展开

  • 栈和堆空间

  • 垃圾回收

  • 解释器和编译器

一.栈空间和堆空间

先回顾下基本知识

1.静态语言就是强类型?二者的关系

(1-1)静态语言, 使用前 要确定数据类型
(1-2)动态语言, 运行中 检查数据类型;
(2-1)弱类型语言,支持隐式类型转换
(2-2)强类型,不支持 隐式转换;
C是静态语言,但是它支持隐式转换,是弱类型

2.JS的内存空间

(1)分三块,代码空间,栈stack空间,堆heap空间;
(2) 原始 类型的数据值都是直接保存在“栈”中的, 引用 类型的值是存放在“堆”中的
栈空间比较小,堆空间比较大;

(3)为什么不放在一起?
放在一起,会影响执行上下文切换和执行效率;
(4)闭包的内存模型,Closure
比如下面这段代码,foo中有个闭包对象,有两个属性值 myName和test1,存到堆中;

1234567891011121314
function foo() {  var myName = "悬笔e绝"  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("张三")bar.getName()console.log(bar.getName())

执行到foo 函数中“return innerBar” 的调用栈情况,如下图

二.垃圾回收机制

1.常用的垃圾回收机制如下:

1-1.标记清除法;

给存储在内存中的变量都加上标记,判断哪些变量没有在执行环境中引用,进行删除;

1-2.引用计数法;

(1)跟踪记录每个值被引用的次数
(2)当声明变量并将一个引用类型的值赋值给该变量时,则这个值的引用次数加1,
(3)同一值被赋予另一个变量,该值的引用计数加1 。
(4)当引用该值的变量被另一个值所取代,则引用计数减1,
(5)当计数为 0 的时候,说明无法在访问这个值了,系统将会收回该值所占用的内存空间。

缺点 :循环引用的时候,引用次数不为0,不会被释放;

调用栈中的数据的GC

1.调用栈还有一个记录当前执行状态的 指针 (称为 ESP)
JS引擎通过下移ESP指针来销毁 栈顶 某个执行上下文的过程。
如下图,上面按个已经是无效的,有新的会直接覆盖;

堆空间中数据的GC

1.代际假说和分代收集~新生代,老生代;

(0)提高垃圾回收的效率,V8将堆分为 新生代 和 老生代 两个部分,
(1)其中新生代为存活时间较短的对象(需要经常进行垃圾回收),内存占用小,GC频繁;
只支持1-8M容量;使用副垃圾回收器;
(2)而老生代为存活时间较长的对象(垃圾回收的频率较低),内存占用多,GC不频繁;
使用主垃圾回收器;

2.新生代的GC算法

新生代的对象通过 Scavenge 算法进行GC。在 Scavenge 的具体实现中,主要采用了 Cheney 算法。
(1)Cheney 算法是一种采用 停止复制(stop-copy) 的方式实现的垃圾回收算法。
(2)它将堆内存一分为二,每一部分空间成为 semispace-半空间。
(3)在这两个 semispace 空间中,只有一个处于使用中,另一个处于闲置中。
(4)处于使用中的 semispace 空间成为 From 对象空间,处于闲置状态的空间成为 To 空闲空间。
(5)当我们分配对象时,先是在 From 空间中进行分配。当开始进行垃圾回收时,会检查 From 空间中的存活对象,这些存活对象将被复制到 To 空间中,同时还会将这些对象有序的排列起来~~相当于内存整理,所以没有内存碎片,而非存活对象占用的空间将被释放。
完成复制后,From空间和To空间的角色发生对换。
(6)Scavenge 是典型的 空间换取时间 的算法,而且复制需要时间成本,无法大规模地应用到所有的垃圾回收中,但非常适合应用在新生代中进行快速频繁清理。

3.对象晋升策略

(1)对象从新生代中移动到老生代中的过程称为晋升。
(2)晋升条件主要有两个:
(1)对象是否经历过 两次 Scavenge 回收都未清除,则移动到老生代
(2)To 空间已经使用超过 25% ,To 空间对象移动到老生代
因为这次 Scavenge 回收完成后,这个 To 空间将变成 From 空间,接下来的内存分配将在这个空间中进行,如果占比过高,会影响后续的内存分配

4.写屏障

写缓冲区中有一个列表(CrossRefList),列表中记录了所有老生区对象指向新生区的情况
这样可以快速找到指向新生代该对象的老生代对象,根据他是否活跃,来清理这个新生代对象;

5.老生代的GC

(1)老生代的内存空间较大且存活对象较多,使用新生代的Scavenge 复制算法,会耗费很多时间,效率不高;而且还会浪费一半的空间;
(2)为此V8使用了 标记-清除算法 (Mark-Sweep) 进行垃圾回收,并使用 标记-压缩算法 (Mark-Compact) 整理内存碎片,提高内存的利用率。步骤如下:

1) 对老生代进行第一遍扫描,标记存活的对象
从一组根元素开始,递归遍历这组根元素,在这个遍历过程中,能到达的元素称为活动对象,没有到达的元素就可以判断为垃圾数据;
2) 对老生代进行第二次扫描,清除未被标记的对象

3) 标记-整理算法,标记阶段一样是递归遍历元素,整理阶段是将存活对象往内存的一端移动

4) 清除掉存活对象边界外的内存
注意,不管哪种,整理内存后只要地址有变化,需要及时更新到调用栈的;

6.全停顿Stop-The-World

(1)JavaScript 是运行在主线程之上的,一旦执行垃圾回收算法,都需要将正在执行的 JavaScript 脚本暂停下来,待垃圾回收完毕后再恢复脚本执行。我们把这种行为叫做全停顿(Stop-The-World);
(2)新生代因为内存小,活动对象少,全停顿影响不大,但是老生代可能会造成卡顿明显;
(3)解决办法~ 增量标记算法Incremental Marking
V8 将标记过程分为一个个的子标记过程,同时让垃圾回收标记和 JavaScript 应用逻辑交替进行,直到标记阶段完成;

三.编译器和解释器

1.编译器Compiler和解释器Interpreter

按语言的执行流程,可以把语言划分为编译型语言和解释型语言。

1-1.编译型语言

在程序执行之前,需要经过编译器的编译过程,并且编译之后会直接保留机器能读懂的二进制文件,这样每次运行程序时,都可以直接运行该二进制文件,而不需要再次重新编译了。比如 C/C++、GO 等都是编译型语言。

1-2.解释型语言

在每次运行时都需要通过解释器对程序进行动态解释和执行。比如 Python、JavaScript 等都属于解释型语言。

2.V8执行一段代码流程图

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

2-1-1.AST

(1)编译器或解释器,他们不理解高级语言,只可以理解AST;
(2)简单demo,在线AST网站
https://resources.jointjs.com/demos/javascript-ast
(3)可以把 AST 看成代码的结构化表示;
(4)应用非常广泛
1)Babel:
Babel 的工作原理就是先将 ES6 源码转换为 AST,然后再将 ES6 语法的 AST 转换为 ES5 语法的 AST,最后利用 ES5 的 AST 生成 JavaScript 源代码;
2)ESLint:
利用 AST 来检查代码规范化的问题。

2-1-2.AST生成过程

(1)分词 tokenize ,或词法分析
将一行行的源码拆解成一个个 token。
token,指的是语法上不可能再分的、最小的单个字符或字符串;
比如:

1
var myName = "悬笔e绝";

关键字“var” ~ keyword、
标识符“myName” ~ identifier、
赋值运算符“=” ~ assignment、
字符串“悬笔e绝” ~ Literal
四个都是 token,而且它们代表的属性还不一样;

(2)解释 parse ,或语法分析
上一步生成的 token 数据,根据语法规则转为 AST。如果源码符合语法规则,这一步就会顺利完成。但如果源码存在语法错误,这一步就会终止,并抛出一个“语法错误”。

2-1-3.执行上下文

前面介绍过,主要是代码在执行过程中的环境信息

2-2.生成字节码

(1)解释器Ignition
根据AST生成 字节码 ,并解释执行字节码;
(2)历史,一开始直接把AST转成机器码,
效率性能很高,但是机器码占用内存很大,小内存手机上内存占用问题明显,
V8团队画了快4年时间,引入字节码,抛弃编译器,才有现在的架构;
(3)字节码
字节码就是介于 AST 和机器码之间的一种代码。但是与特定类型的机器码无关,字节码需要通过解释器将其转换为机器码后才能执行。

2-3.执行代码

(1)如果有一段第一次执行的字节码,解释器 Ignition 会逐条解释执行。
解释器 Ignition 除了负责生成字节码之外,还有一个作用,就是解释执行字节码。
(2)在 Ignition 执行字节码的过程中,如果发现有 热点代码(HotSpot) ,比如一段代码被重复执行多次,这种就称为热点代码,后台的编译器 TurboFan 就会把它编译为高效的 机器码 ,然后当再次执行这段被优化的代码时,只需要执行编译后的机器码就可以了,这样就大大提升了代码的执行效率。
(3)V8 的解释器和编译器的取名
解释器Ignition ~ 点火器;
编译器TurboFan ~ 涡轮增压发动机;
寓意着代码启动时通过点火器慢慢发动,一旦启动,涡轮增压介入,其执行效率随着执行时间越来越高效率;
(4)即时编译 JIT
字节码配合解释器和编译器的技术;
Java 和 Python 的虚拟机,苹果的 SquirrelFish Extreme 和 Mozilla 的 SpiderMonkey 也是基于JIT这个技术;

3.V8做的性能优化措施

(1)脚本流
一边下载,一边解析,节省时间;
(2)字节码缓存
访问同一个页面时直接复用之前的字节码,不再重新编译生成;
(3)内联
将主函数中调用的函数,直接换成要执行的语句;加快执行速度;
(4)隐藏类
通过隐藏类快速定位到动态加入的属性;注意:动态加入的属性顺序不一样,会造成生成不同的隐藏类,我们动态赋值同一个构造函数对象的时候,尽量保证顺序也是一致的。
(5)JIT即时编译,将热点代码编译成机器码
执行越久,越多的代码编译成机器码,速度越快;
常用的函数传入的类型保持固定。并且对象的属性越稳定,越有利于性能。

总结

这篇只是V8引擎的入门介绍,关于V8的其他知识,后续会补充其他的文章
未完待续……

javascript清除map所占内存_【原创.54期】 JavaScript的V8引擎初探相关推荐

  1. 微信小程序超级占内存_微信小程序占用内存小,用户再也不用担心内存不足问题了...

    内存占用小,微信小程序,让用户再也不用担心小程序不足内存问题了,时下,一站式支持常用APP(手机应用软件)的微信小程序受到市民青睐. 微信小程序,是一种不需要下载安装即可使用的应用,它实现了应用&qu ...

  2. win10msmpeng占内存_微软win10吃内存,CPU占用高,没有优化好?做好这3点系统快如飞...

    随着win7更新关闭日期的到来,还剩两天时间了,届时微软将不在为win7提供补丁了,安全问题就会日益严重,尽管win7使用起来很省内存,CPU占用不高,但安全问题大于一切,使用win10就成了大多数网 ...

  3. golang MySQL 占内存_使用golang插入mysql性能提升經驗

    前言 golang可以輕易制造高並發,在某些場景很合適,比如爬蟲的時候可以爬的更加高效.但是對應某些場景,如文件讀寫,數據庫訪問等IO為瓶頸的場合,就沒有什么優勢了. 前提基礎 1.golang數據庫 ...

  4. 微信小程序超级占内存_实测:微信小程序究竟会占用多少内存?结果竟然

    上图就是小编微信中已经安装的小程序列表.微信占用的内存空间数据.接下来小编安装两个小程序. 上图就是安装小程序之后的结果,可以看出,安装程序对内存空间影响几乎没有.(可能是极小,小到可以忽略不计.) ...

  5. 微信小程序超级占内存_实测:微信小程序占多少内存?或许真没有你想象的那么“小”!...

    微信全新功能"小程序"在今天正式开放.不过不少网友对于小程序还是有不少的疑问,其中最让网友关心的问题就是小程序究竟占用多少手机内存空间呢? (ps. 为了让大众理解,这里说的手机& ...

  6. win10msmpeng占内存_小编详解win10一开机内存就占了5g的详细处理方式

    我们在操作电脑系统的过程中可能就会遇到win10一开机内存就占了5g的问题,这个win10一开机内存就占了5g问题还难到了一些平时很懂win10的网友,要是你想马上解决win10一开机内存就占了5g的 ...

  7. win10msmpeng占内存_彻底解决win10 占用内存高的办法

    希望大家多多转发,帮助更多的人 必要前提:系统不能有任何已安装更新包 因为有个更新包bug (不知道哪个)导致内存(我是8G DDR2133)飙高 16G  32G也抗不住 网上方法都是废话没一个靠谱 ...

  8. 微信小程序超级占内存_手机APP占内存?4款超赞的微信小程序,不用下载,拿去即可使用!...

    小程序是很多朋友都爱使用,不是因为新鲜,而是应为它实用,还没找到合适的小程序,大家可以看看今天小编为大家分享的4款不错的小程序. 1.WiFi一键联 这款小程序它会自动帮你显示并连接周围的WiFi,让 ...

  9. javascript 权威指南第7版_第七版 JavaScript 权威指南之异步

    一些计算程序,比如科学模拟和机器学习模型,是计算密集型[compute-bound]的.它们不间断地运行直到得到结果. 大多数现实世界的程序,则是异步的.浏览器里的 JavaScript 程序是典型的 ...

最新文章

  1. rtsp有没有好使_轻量级RTSP服务和内置RTSP网关有什么不同?
  2. 不用重装系统,Win7下直接开启ACHI
  3. ubuntu14.04 LTS 更新源
  4. 【Tools】Wireshark3.0安装教程详解
  5. 【机器学习】降维技术-PCA
  6. 文件重命名批量处理(Matlab)
  7. react学习(61)--js contact
  8. 以太网接口MII,RMII,SMII,GMII总线接口简介
  9. python播放音乐-python 模拟(简易)音乐播放器
  10. Kazrog AmpCraft 1992 for Mac - 放大器建模插件
  11. pat-A1043:Is it a Binary Search Tree(二叉搜索树和及其镜像树的遍历)
  12. 荣耀9.0系统怎么无需root激活XPOSED框架的教程
  13. 全球及中国ISO刀柄行业产销需求及消费策略调研报告2022版
  14. Error: [vuex] do not mutate vuex store state outside mutation handlers.
  15. 【YOLOv5实战2】基于YOLOv5的交通标志识别系统-自定义数据集
  16. 应该怎么提升4G工业路由器的无线信号?
  17. Spring5:p命名和c命名空间注入
  18. python signal处理
  19. [个人学习]透视画法的一点记录
  20. 开源CRM+SaaS云服务的生态模式能否撬动中国管理软件市场?

热门文章

  1. linux rpm命令 查询包安装与否、包详细信息、包安装位置、文件属于哪个包、包依赖
  2. DirectX和DirectShow介绍和区别
  3. 得到win7 win8的桌面句柄
  4. PCA--主成分分析(Principal components analysis)-最小平方误差解释
  5. Python学习之For训练
  6. kvm性能优化方案---cpu/内存/磁盘/网络
  7. js 浅拷贝直接赋值_js的浅拷贝和深拷贝的简单理解和使用方法
  8. mysql预处理 更新_MySQL 预处理方法更新删除-2018年04月27日00时59分
  9. java 端口8161_ActiveMQ_Windows和Linux版本的安装部署
  10. python如何输出多个星号_如何将 Python 的一个类方法变为多个方法?