乐趣区

关于前端:jsliang-求职系列-19-垃圾回收

一 目录

不折腾的前端,和咸鱼有什么区别

目录
一 目录
二 前言
三 栈垃圾回收
四 堆垃圾回收
五 新生代和老生代
 5.1 新生代 – 副垃圾回收器
 5.2 老生代 – 主垃圾回收器
六 全进展
七 参考文献

二 前言

返回目录

原始数据类型是存储在栈空间中的,援用类型的数据是存储在堆空间中的。

不过有些数据被应用之后,可能就不再须要了,咱们把这种数据称为垃圾数据。

如果这些垃圾数据始终保留在内存中,那么内存会越用越多。

所以咱们须要对这些垃圾数据进行回收,以开释无限的内存空间。

这时候就引入了垃圾回收机制。

垃圾回收策略分为 手动回收 主动回收 两种:

  • 手动回收:C/C++ 语言能够通过 free() 这些代码来决定何时分配内存、何时销毁内存。
  • 主动回收:JavaScript、Python、Java 等产生的垃圾数据是由垃圾回收器来开释的。

三 栈垃圾回收

返回目录

当函数执行完结,JavaScript 引擎通过向下挪动 ESP 指针(记录调用栈以后执行状态的指针),来销毁该函数保留在栈中的执行上下文(变量环境、词法环境、thisouter)。

如果有代码:

function foo(){
  var a = 1;
  var b = {name: 'jsliang'};
  function showName(){
    var c = 2;
    var d = {name: 'zhazhaliang'};
  }
  showName();}
foo();

在下面代码中,依据浏览器策略:

  1. 先到全局执行上下文
  2. 再到 foo 函数执行上下文
  3. 最初到 showName 函数执行上下文

依据栈的个性,此时 JavaScript 状况应为:

调用栈
showName 函数执行上下文
foo 函数执行上下文
全局执行上下文

而后开始开释过程:

  1. 执行到 showName 函数的时候,创立 showName 函数的执行上下文,并将 showName 函数的执行上下文压入栈中。
  2. 以此同时,咱们会有一个记录以后执行状态的指针(称为 ESP),指向调用栈中 showName 函数的执行上下文,示意以后正在执行 showName 函数。
  3. showName 函数执行结束,函数执行流程进入 foo 函数,这时候 ESP 就下移到 foo 函数的执行上下文。这个下移操作就是销毁 showName 函数执行上下文的过程。

如果 showName 函数上面还调用了另一个函数,那么它会笼罩 showName 函数的内容,用来寄存另一个函数的执行上下文。

就是说:当一个函数执行完结之后,JavaScript 引擎会通过向下挪动 ESP 来销毁保留栈中的执行上下文。

四 堆垃圾回收

返回目录

在下面,咱们将栈中的垃圾通过 ESP 进行回收了:

function foo(){
  var a = 1;
  var b = {name: 'jsliang'};
  function showName(){
    var c = 2;
    var d = {name: 'zhazhaliang'};
  }
  showName();}
foo();

然而,外面的 bd 其实是仍旧存在于堆中的。

要回收对象的垃圾数据,就须要 JavaScript 中的垃圾回收器了。

五 新生代和老生代

返回目录

代际假说特点:

  1. 大部分对象存活工夫很短
  2. 不被销毁的对象,会活的更久

这两个特点不仅仅实用于 JavaScript,同样实用于大多数的动静语言,如 Java、Python 等。

V8 中会把堆分为 新生代 老生代 两个区域,新生代中寄存的是生存工夫短的对象,老生代中寄存的生存工夫久的对象。

新生区的容量没有老生区那么大,所以 V8 别离应用 2 个不同的垃圾回收器,来高效施行垃圾回收:

  • 副垃圾回收器。次要负责新生代的垃圾回收。
  • 主垃圾回收器。次要负责老生代的垃圾回收。

5.1 新生代 – 副垃圾回收器

返回目录

算法:Scavenge 算法

对象区域 闲暇区域

原理:

  1. 把新生代空间对半划分为两个区域,一半是对象区域,一半是闲暇区域。
  2. 新退出的对象都会寄存到对象区域,当对象区域快被写满时,就须要执行一次垃圾清理操作。
  3. 先对对象区域中的垃圾做标记,标记实现之后,把这些存活的对象复制到闲暇区域中
  4. 实现复制后,对象区域与闲暇区域进行角色翻转,也就是原来的对象区域变成闲暇区域,原来的闲暇区域变成了对象区域。

对象降职策略:通过两次垃圾回收仍然还存活的对象,会被挪动到老生区中。

5.2 老生代 – 主垃圾回收器

返回目录

  • 算法:标记 – 革除(Mark-Sweep)算法
  • 原理:
  1. 标记:标记阶段就是从一组根元素开始,递归遍历这组根元素,在这个遍历过程中,能达到的元素称为流动对象,没有达到的元素就能够判断为垃圾数据。
  2. 革除:将垃圾数据进行革除。

对一块内存屡次执行标记 – 革除算法后,会产生大量不间断的内存碎片。而碎片过多会导致大对象无奈调配到足够的间断内存。

这时候就须要标记整顿。


  • 算法:标记 – 整顿(Mark-Compact)算法
  • 原理:
  1. 标记:和标记 – 革除的标记过程一样,从一组根元素开始,递归遍历这组根元素,在这个遍历过程中,能达到的元素标记为流动对象。
  2. 整顿:让所有存活的对象都向内存的一端挪动
  3. 革除:清理掉端边界以外的内存

六 全进展

返回目录

因为 JavaScript 是单线程的,所以一旦执行垃圾回收算法,那正在执行的 JavaScript 脚本须要暂停下来,等垃圾回收结束之后再复原脚本执行。

这种行为叫 全进展(Stop-The-World)

如果堆中的数据较多,那么回收须要工夫,会造成页面卡顿状态,所以为了升高这个卡顿,V8 将标记过程分为一个一个子标记过程,同时垃圾回收标记和 JavaScript 应用逻辑交替进行。

  • 优化算法:增量标记(Incremental Marking)算法
  • 原理:
  1. 为了升高老生代的垃圾回收而造成的卡顿
  2. V8 把一个残缺的垃圾回收工作拆分为很多小的工作
  3. 让垃圾回收标记和 JavaScript 应用逻辑交替进行

七 参考文献

返回目录

  • JavaScript 进阶 - 内存机制(表情包初探)【浏览倡议:20min】

jsliang 的文档库由 梁峻荣 采纳 常识共享 署名 - 非商业性应用 - 雷同形式共享 4.0 国内 许可协定 进行许可。<br/> 基于 https://github.com/LiangJunrong/document-library 上的作品创作。<br/> 本许可协定受权之外的应用权限能够从 https://creativecommons.org/licenses/by-nc-sa/2.5/cn/ 处取得。

退出移动版