V8工作原理

栈空间和堆空间

  • JavaScript是一种弱类型(支持隐式类型转换)的、动态(运行过程中需要检查数据类型)的语言。

    • JavaScript数据类型
    1. Boolean
    2. String
    3. Number
    4. Null
    5. Undefined
    6. Symbol
    7. BigInt
    8. Object
  • 内存空间

    • 代码空间
    • 栈空间

      • 原始类型的数据值都是直接保存在“栈”中,原始类型的赋值会完整复制变量值。
      • 栈的空间一般不会设置太大,主要存放一些原始类型的小数据
    • 堆空间

      • 引用类型的值存放在“堆中”,引用类型的赋值是复制引用地址。
      • 引用类型的数据占用空间都比较大,堆空间很大,可以存放很多大的数据。

垃圾回收

  • 调用栈的数据回收

    • JavaScript引擎会通过向下移动ESP(记录当前执行状态的指针)来销毁该函数保存在栈中的 上下文。
  • 堆中数据回收

    • JavaScript垃圾回收器
    • 两个垃圾回收领域的术语

      • 代际假说

        • 特点1:大部分对象在内存中存在的时间都很短
        • 特点2:不死的对象,会活得更久
      • 分代假说
    • V8中会把堆分为新生代和老生代两个区域,新生代中存放的是生存时间短的对象;老生代中存放的生存时间久的对象。
    • 副垃圾回收器,主要负责新生代的垃圾回收
    • 主垃圾回收器,主要负责老生代的垃圾回收

      • 垃圾回收器的工作流程
    • 共同的执行流程

      1. 标记空间中活动对象和非活动对象
      2. 回收非活动对象的所占内存
      3. 内存整理
    • 副垃圾回收器

      • 负责新生代区的垃圾回收,把新生代空间对半划分为两个区域,一半是对象区域,一半是空闲区域(Scavenge算法)。
      • 新加入的对象都会存放到对象区域,当内存快被写满时,就要执行一次垃圾清理工作。
      • 在垃圾回收过程中,首先要对对象区域中的垃圾做标记。标记完成之后,就进入垃圾清理阶段,副垃圾回收器会把这些存活的对象复制到空闲区域中,并把这些对象有序的排列起来。
      • 完成复制之后后,对象区域和空闲区域进行角色翻转。这种角色翻转的操作还能让新生代中这两块区域无限重复使用下去。
      • 为了执行效率,一般新生代的空间会被设置的比较小
      • 对象晋升策略,如果进行两次垃圾回收还存活的对象,会被移到老生区中。
    • 主垃圾回收器

      • 主垃圾回收器主要负责老生区中的垃圾回收。
      • 老生区对象的两个对象:一是对象占用空间大,二是对象存活时间长。
      • 主垃圾回收器是采用标记-清除(Mark-Sweep)算法进行垃圾回收的。
      • 首先是标记阶段,从一组根元素开始,递归遍历这组根元素,遍历过程中,能够达到的成为活动对象,不能达到的元素可以判断为垃圾数据。
      • 垃圾清除阶段,清除标记为垃圾标记的数据。
      • 标记-清除(Mark-Sweep)算法会产生大量的不连续内存碎片,会导致大对象无法分配到足够的连续内存。需要标记-整理(Mark- Compact),标记过程与标记-清除的标记过程是一样的。而整理步骤是让活动对象向一端移动,然后清除掉端边界以外的内存
    • 全停顿

      • JavaScript是运行在主线程之上的,一段执行垃圾回收算法,都需要将JavaScript脚本停止下来,待垃圾回收完毕之后再恢复脚本执行。这种行为叫做全停顿。
      • 在V8新生代的垃圾回收中,因其内存占用小,存活对象少,所以全停顿影响不大。
      • 为了降低老生代的垃圾回收而造成的卡顿,V8将标记过程拆分成一个个的子标记过程,同时让垃圾回收标记与JavaScript应用逻辑交替执行,直到标记过程完成。这个算法成为增量算法(Incremental Marking)。使用增量标记算法,可以将垃圾回收任务拆成很多小的任务。这些小的任务执行时间较短,可以穿插在其他JavaScript任务中间执行。

        • 思考:
    • 堆中的经过垃圾回收整理之后,活动的对象内存地址改变了,内存变化如何更新到对应的执行上下文中?
此文章为4月Day8学习笔记,内容来源于极客时间《浏览器原理》,学习使我快乐,每天进步一点点💪💪

豪猪
4 声望4 粉丝

undefined